杰瑞科技汇

python qprocessbar

Of course! The QProgressBar is a fundamental widget in PyQt (and PySide) used to give visual feedback to the user about the progress of a long-running operation. It's an essential part of creating a user-friendly application.

Here’s a comprehensive guide covering everything from basic usage to advanced features.


Basic QProgressBar

Let's start with the simplest example. We'll create a progress bar and a button. When the button is clicked, the progress bar will fill up gradually.

Key Concepts:

  • QProgressBar(QWidget): The constructor. It's a widget, so it needs a parent.
  • setValue(int): Sets the progress bar's value. The range is defined by setMinimum() and setMaximum(). By default, it's 0 to 100.
  • setMinimum(int) / setMaximum(int): Sets the lower and upper bounds of the progress bar.
  • setRange(int, int): A convenient way to set both minimum and maximum at once.

Code:

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButton, QProgressBar
from PyQt5.QtCore import Qt, QThread, pyqtSignal
# --- Basic Example ---
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QProgressBar Basic Example")
        self.setGeometry(100, 100, 400, 150)
        # Create a central widget and a layout
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        layout = QVBoxLayout(central_widget)
        # Create the progress bar
        self.progress_bar = QProgressBar()
        # Set the range (e.g., 0 to 100)
        self.progress_bar.setRange(0, 100)
        # Optional: Set text format
        self.progress_bar.setFormat("%p%") # Shows percentage (e.g., 50%)
        # Create a button to start the "process"
        self.start_button = QPushButton("Start Process")
        self.start_button.clicked.connect(self.start_progress)
        # Add widgets to the layout
        layout.addWidget(self.progress_bar)
        layout.addWidget(self.start_button)
    def start_progress(self):
        """Simulates a process by incrementing the progress bar."""
        # Disable the button to prevent multiple clicks
        self.start_button.setEnabled(False)
        # Reset the progress bar
        self.progress_bar.setValue(0)
        # Simulate work in a loop
        for i in range(101):
            self.progress_bar.setValue(i)
            # A small delay to make the progress visible
            # In a real app, you would not use sleep in the main thread!
            # This is just for demonstration.
            import time
            time.sleep(0.02)
        # Re-enable the button
        self.start_button.setEnabled(True)
# --- Main Execution ---
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

Handling Long-Running Tasks (The Correct Way)

The example above is bad practice because it uses time.sleep() in the main GUI thread. This will freeze the application. The user cannot move the window, click other buttons, or even close it.

The correct way to handle long-running tasks is to use a QThread. The main thread (GUI) will not be blocked.

Key Concepts:

  • QThread: Provides a way to run a task in a separate thread.
  • pyqtSignal: A mechanism for communication between the worker thread and the main GUI thread. The worker thread emits a signal, and the main thread connects it to a slot (a function) that updates the progress bar.

Code (The Recommended Approach):

We'll create a Worker class that inherits from QThread and a pyqtSignal to send progress updates.

import sys
import time
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QPushButton, QProgressBar
from PyQt5.QtCore import QThread, pyqtSignal
# 1. Create a Worker class that inherits from QThread
class Worker(QThread):
    # Define a signal to send the progress value
    progress_signal = pyqtSignal(int)
    def run(self):
        """This method runs in the separate thread."""
        print("Worker thread started.")
        for i in range(101):
            # Simulate some work
            time.sleep(0.05) 
            # Emit the signal with the current progress
            self.progress_signal.emit(i)
        print("Worker thread finished.")
# 2. Modify the MainWindow to use the Worker
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QProgressBar with QThread")
        self.setGeometry(100, 100, 400, 150)
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        layout = QVBoxLayout(central_widget)
        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0, 100)
        self.progress_bar.setFormat("%p%")
        self.start_button = QPushButton("Start Long Task")
        self.start_button.clicked.connect(self.start_task)
        layout.addWidget(self.progress_bar)
        layout.addWidget(self.start_button)
        # We will store the worker instance here
        self.worker = None
    def start_task(self):
        # Disable the button to prevent multiple tasks
        self.start_button.setEnabled(False)
        self.progress_bar.setValue(0)
        # Create a new worker instance
        self.worker = Worker()
        # Connect the worker's signal to the progress bar's update slot
        self.worker.progress_signal.connect(self.update_progress)
        # Optional: Connect a signal to know when the thread has finished
        self.worker.finished.connect(self.task_finished)
        # Start the thread
        self.worker.start()
    def update_progress(self, value):
        """This slot is called from the main thread when the signal is emitted."""
        self.progress_bar.setValue(value)
    def task_finished(self):
        """This slot is called when the worker thread is finished."""
        print("Task finished in main window.")
        self.start_button.setEnabled(True)
# --- Main Execution ---
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

Customizing the QProgressBar

QProgressBar has several properties to change its appearance.

Key Properties:

  • setFormat(QString): Defines the text displayed on the progress bar.
    • %p: Percentage (e.g., "50%").
    • %v: Current value (e.g., "50").
    • %m: Maximum value (e.g., "100").
    • "%p% (%v/%m)": "50% (50/100)".
  • setAlignment(Qt.Alignment): Aligns the text inside the bar (Qt.AlignLeft, Qt.AlignCenter, Qt.AlignRight).
  • setInvertedAppearance(bool): Reverses the direction of the fill.
  • setTextVisible(bool): Hides or shows the text. Useful if you only want the visual bar.
  • setOrientation(Qt.Orientation): Changes the orientation to Qt.Vertical.

Code Example (Customization):

# ... (imports are the same as the basic example)
class CustomizedWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Customized QProgressBar")
        self.setGeometry(100, 100, 400, 250)
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        layout = QVBoxLayout(central_widget)
        # --- Horizontal Bar 1 ---
        self.h_bar1 = QProgressBar()
        self.h_bar1.setRange(0, 1000)
        self.h_bar1.setFormat("Value: %v / 1000")
        self.h_bar1.setAlignment(Qt.AlignCenter)
        # --- Horizontal Bar 2 (Inverted) ---
        self.h_bar2 = QProgressBar()
        self.h_bar2.setRange(0, 100)
        self.h_bar2.setFormat("%p%")
        self.h_bar2.setInvertedAppearance(True) # Fills from right to left
        self.h_bar2.setTextVisible(False) # Hide text for a cleaner look
        # --- Vertical Bar ---
        self.v_bar = QProgressBar()
        self.v_bar.setRange(0, 100)
        self.v_bar.setOrientation(Qt.Vertical)
        self.v_bar.setFormat("%p%")
        self.v_bar.setAlignment(Qt.AlignHCenter) # Text alignment for vertical bar
        # Button to start a demo
        self.start_button = QPushButton("Run Demo")
        self.start_button.clicked.connect(self.run_demo)
        layout.addWidget(self.h_bar1)
        layout.addWidget(self.h_bar2)
        layout.addWidget(self.v_bar)
        layout.addWidget(self.start_button, alignment=Qt.AlignCenter)
    def run_demo(self):
        self.start_button.setEnabled(False)
        # A simple way to update multiple bars
        for i in range(101):
            self.h_bar1.setValue(i * 10)
            self.h_bar2.setValue(i)
            self.v_bar.setValue(i)
            QApplication.processEvents() # Keep the UI responsive
            time.sleep(0.02)
        self.start_button.setEnabled(True)
# --- Main Execution ---
if __name__ == '__main__':
    app = QApplication(sys.argv)
    # To run this example, you would create an instance of CustomizedWindow
    # window = CustomizedWindow()
    # window.show()
    # sys.exit(app.exec_())

Styling with QSS (Qt Style Sheets)

You can give your progress bar a completely custom look using Qt Style Sheets, similar to CSS for web pages.

Key CSS Selectors:

  • QProgressBar: The widget itself.
  • QProgressBar::chunk: The part of the bar that is filled.

Code Example (Styling):

# ... (imports are the same as the basic example)
class StyledWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Styled QProgressBar")
        self.setGeometry(100, 100, 400, 150)
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        layout = QVBoxLayout(central_widget)
        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0, 100)
        self.start_button = QPushButton("Start Process")
        self.start_button.clicked.connect(self.start_progress)
        layout.addWidget(self.progress_bar)
        layout.addWidget(self.start_button)
        # Apply the style sheet
        self.setStyleSheet("""
            QProgressBar {
                border: 2px solid grey;
                border-radius: 5px;
                text-align: center;
                background-color: #f0f0f0;
            }
            QProgressBar::chunk {
                background-color: #05B8CC; /* A nice blue color */
                width: 20px; /* Optional: set a fixed width for chunks */
                margin: 1px; /* Optional: add space between chunks */
            }
        """)
    def start_progress(self):
        # (Same logic as the basic example, but with QThread in a real app)
        self.start_button.setEnabled(False)
        self.progress_bar.setValue(0)
        for i in range(101):
            self.progress_bar.setValue(i)
            QApplication.processEvents()
            time.sleep(0.02)
        self.start_button.setEnabled(True)
# --- Main Execution ---
if __name__ == '__main__':
    app = QApplication(sys.argv)
    # window = StyledWindow()
    # window.show()
    # sys.exit(app.exec_())

Summary

Feature Method/Property Description
Basic Setup QProgressBar() Create the widget.
setRange(min, max) Define the progress scale.
setValue(value) Set the current progress.
Text setFormat("...%p%...") Customize the displayed text.
setTextVisible(True/False) Show or hide the text.
Orientation setOrientation(Qt.Vertical) Change to a vertical progress bar.
Long Tasks QThread + pyqtSignal The correct way to avoid freezing the GUI.
Styling setStyleSheet(...) Use CSS-like syntax for custom appearance.
QProgressBar (selector) Styles the main widget (border, background).
QProgressBar::chunk (selector) Styles the filled part of the bar.
分享:
扫描分享到社交APP
上一篇
下一篇