警告:此页面上的示例混合了 PyQt3 和 PyQt4,请谨慎使用!

本教程旨在提供一个动手指南,帮助您学习如何用 Python 构建一个小型 Qt4 应用程序的基础知识。

要跟随本教程,您应该具备基本的 Python 知识,但不需要了解 Qt4。在这些示例中,我使用的是 Linux,并假设您已经安装并正确配置了 Python 和 PyQt4。要测试这一点,请打开一个 Python shell(在终端中输入 'python' 启动交互式解释器),然后输入:

>>> import PyQt4

如果没有出现错误信息,您应该可以开始了。

本教程中的示例尽可能简单,展示了编写和构建程序的有用方法。重要的是,您需要阅读示例文件的源代码,大部分解释都在代码中。最好的方法是通过玩弄这些示例并尝试修改它们,来熟悉 PyQt。

你好,世界!

让我们从简单的开始:弹出一个窗口并显示内容。以下这个小程序将弹出一个窗口,显示 "Hello, world!"。

#!/usr/bin/env python

import sys
from PyQt4 import Qt

# 我们实例化一个 QApplication,并将脚本的参数传递给它:
a = Qt.QApplication(sys.argv)

# 为这个应用程序添加一个基本的小部件:
# 第一个参数是我们希望 QWidget 显示的文本,第二个参数是父小部件。
# 由于 "hello" 是我们唯一使用的控件(所谓的“MainWidget”),它没有父控件。
hello = Qt.QLabel("Hello, World")

# ... 然后让它显示出来。
hello.show()

# 现在我们可以启动它了。
a.exec_()

大约 7 行代码,这就是最简单的实现。

按钮

让我们添加一些交互!我们将用一个按钮替换显示 "Hello, World!" 的标签,并为按钮指定一个动作。这个指定是通过将信号(按钮被点击时发送的事件)连接到槽(槽是一个动作,通常是函数,在该事件发生时执行)来完成的。

#!/usr/bin/env python

import sys
from PyQt4 import Qt

a = Qt.QApplication(sys.argv)

# 当按钮被点击时调用的函数
def sayHello():
    print("Hello, World!")

# 实例化按钮
hellobutton = Qt.QPushButton("Say 'Hello world!'")

# 将动作 "sayHello" 连接到事件 "按钮被点击"
hellobutton.clicked.connect(sayHello)

# 其余部分已经知道了...
# a.setMainWidget(hellobutton)
hellobutton.show()
a.exec_()

你可以想象,这种编码方式不是可扩展的,也不是你以后想要继续使用的方式。因此,我们来使它更加符合 Python 风格,增加结构,并真正使用面向对象编程。我们创建自己的应用程序,继承自 QApplication,并将应用程序的自定义部分放入其方法中:一个方法用于构建小部件,另一个方法(槽)用于处理接收到的信号时执行的代码。

#!/usr/bin/env python

import sys
from PyQt4 import Qt

class HelloApplication(Qt.QApplication):
    def __init__(self, args):
        """ 在构造函数中,我们做了所有的工作来启动应用程序,
            基本上是通过 __init__ 方法构造一个基本的 QApplication,
            然后添加小部件,最后启动 exec_loop。"""
        Qt.QApplication.__init__(self, args)
        self.addWidgets()

    def addWidgets(self):
        """ 在这个方法中,我们添加小部件,并将这些小部件的信号
            连接到我们的方法,也就是所谓的“槽” """
        self.hellobutton = Qt.QPushButton("Say 'Hello world!'")
        self.hellobutton.clicked.connect(self.slotSayHello)
        self.hellobutton.show()

    def slotSayHello(self):
        """ 这是一个示例槽方法,当信号被发射时会调用该方法 """
        print("Hello, World!")

# 只有在独立运行脚本时,才会执行以下操作,这样我们就能测试应用程序,
# 但如果导入这个程序,它不会执行任何代码。
if __name__ == "__main__":
    app = HelloApplication(sys.argv)
    app.exec_()

这个示例通过创建一个应用程序来实现 PyQt 中的按钮点击事件处理,并通过槽函数进行信号连接,演示了如何用面向对象的方式组织代码。

GUI 编码

...所以我们想使用 Qt3 Designer 来创建我们的 GUI。在图中,你可以看到一个简单的 GUI,绿色的字母标明了控件的名称。我们要做的是:

  1. 我们将 Qt Designer 生成的 .ui 文件编译成一个 Python
  2. 我们继承该并将其用作我们的主窗口部件。

这样,我们就可以在之后从 Qt Designer 中更改用户界面,而不会影响我们添加的代码。

Bash
pyuic4 testapp_ui.ui -o testapp_ui.py

这条命令会生成一个我们可以使用的 Python 文件

我们程序的运作方式可以这样描述:我们在行编辑框中填写内容,点击添加按钮会连接到一个方法,该方法从行编辑框中读取文本,将其转换为一个列表视图项,并添加到我们的列表视图中。点击删除按钮将从列表视图中删除当前选定的项目。以下是带有详细注释的代码(仅在 PyQt3 中有效):

   
     #!/usr/bin/env python

import sys
from PyQt4 import Qt

class HelloApplication(Qt.QApplication):
    def __init__(self, args):
        """ In the constructor we're doing everything to get our application
            started, which is basically constructing a basic QApplication by 
            its __init__ method, then adding our widgets and finally starting 
            the exec_loop."""
        Qt.QApplication.__init__(self, args)
        self.addWidgets()

    def addWidgets(self):
        """ In this method, we're adding widgets and connecting signals from 
            these widgets to methods of our class, the so-called "slots" 
        """
        self.hellobutton = Qt.QPushButton("Say 'Hello world!'")
        self.hellobutton.clicked.connect(self.slotSayHello)
        self.hellobutton.show()

    def slotSayHello(self):
        """ This is an example slot, a method that gets called when a signal is 
            emitted """
        print ("Hello, World!")


# Only actually do something if this script is run standalone, so we can test our 
# application, but we're also able to import this program without actually running
# any code.
if __name__ == "__main__":
    app = HelloApplication(sys.argv)
    app.exec_()
GUI Coding
... so we want to use Qt3 Designer for creating our GUI. In the picture, you can see a simple GUI, with in green letters the names of the widgets. What we are going to do is We compile the .ui file from Qt designer into a python class We subclass that class and use it as our mainWidget This way, we're able to change the user interface afterwards from Qt designer, without having it messing around in the code we added.

pyuic4 testapp_ui.ui -o testapp_ui.py
makes a Python file from it which we can work with.

The way our program works can be described like this: We fill in the lineedit Clicking the add button will be connected to a method that reads the text from the lineedit, makes a listviewitem out of it and adds that to our listview. Clicking the deletebutton will delete the currently selected item from the listview. Here's the heavily commented code (only works in PyQt3):

#!/usr/bin/env python
 
from testapp_ui import TestAppUI
from qt import *
import sys
 
class HelloApplication(QApplication):
    def __init__(self, args):
        """ In the constructor we're doing everything to get our application
            started, which is basically constructing a basic QApplication by 
            its __init__ method, then adding our widgets and finally starting 
            the exec_loop."""
        QApplication.__init__(self, args)
        
        # We pass None since it's the top-level widget, we could in fact leave 
        # that one out, but this way it's easier to add more dialogs or widgets.
        self.maindialog = TestApp(None)
        
        self.setMainWidget(self.maindialog)
        self.maindialog.show()
        self.exec_loop()     


class TestApp(TestAppUI):
    def __init__(self, parent):
        # Run the parent constructor and connect the slots to methods.
        TestAppUI.__init__(self, parent)
        self._connectSlots()

        # The listview is initially empty, so the deletebutton will have no effect,
        # we grey it out.
        self.deletebutton.setEnabled(False)

    def _connectSlots(self):
        # Connect our two methods to SIGNALS the GUI emits.
        self.addbutton.clicked.connect(self._slotAddClicked)
        self.deletebutton.clicked.connect(self._slotDeleteClicked)

    def _slotAddClicked(self):
        # Read the text from the lineedit,
        text = self.lineedit.text()
        # if the lineedit is not empty,
        if len(text):
            # insert a new listviewitem ...
            lvi = QListViewItem(self.listview)
            # with the text from the lineedit and ...
            lvi.setText(0,text)
            # clear the lineedit.
            self.lineedit.clear()

            # The deletebutton might be disabled, since we're sure that there's now
            # at least one item in it, we enable it.
            self.deletebutton.setEnabled(True)

    def _slotDeleteClicked(self):
        # Remove the currently selected item from the listview.
        self.listview.takeItem(self.listview.currentItem())

        # Check if the list is empty - if yes, disable the deletebutton.
        if self.listview.childCount() == 0:
            self.deletebutton.setEnabled(False)


if __name__ == "__main__":
    app = HelloApplication(sys.argv)
also this code is useful and it works on PyQt4 and it has many useful options

#!/usr/bin/env python
# Copyright (c) 2008-10 Qtrac Ltd. All rights reserved.
# This program or module is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation, either version 2 of the License, or
# version 3 of the License, or (at your option) any later version. It is
# provided for educational purposes and is distributed in the hope that
# it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
# the GNU General Public License for more details.
#
#
#   Versions
#
# 1.0.1 Fixed bug reported by Brian Downing where paths that contained
#       spaces were not handled correctly.
# 1.0.2 Fixed bug reported by Ben Thompson that if the UIC program
#       fails, no problem was reported; I try to report one now.
# 1.1.0 Added Remember path option; if checked the program starts with
#       the last used path, otherwise with the current directory, unless
#       overridden on the command line
# 1.1.1 Changed default path on Windows to match PyQt 4.4
# 1.2.1 Changed import style + bug fixes
# 1.2.2 Added stderr to error message output as per Michael Jackson's
#       suggestion
# 1.2.3 Tried to make the paths work on Mac OS X
# 1.2.4 Added more options
# 1.2.5 Use "new-style" connections (src.signal.connect(target.slot) instead of
#       src.connect(src, SIGNAL("signal()"), target.slot)) and improve PEP-8
#       compliance

from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from future_builtins import *

import os
import platform
import stat
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

__version__ = "1.2.5"

Windows = sys.platform.lower().startswith(("win", "microsoft"))

class OptionsForm(QDialog):
    def __init__(self, parent=None):
        super(OptionsForm, self).__init__(parent)

        settings = QSettings()
        if sys.platform.startswith("darwin"):
            pyuic4Label = QLabel("pyuic4 (pyuic.py)")
        else:
            pyuic4Label = QLabel("pyuic4")
        self.pyuic4Label = QLabel(settings.value("pyuic4",
                QVariant(PYUIC4)).toString())
        self.pyuic4Label.setFrameStyle(QFrame.StyledPanel|
                                       QFrame.Sunken)
        pyuic4Button = QPushButton("py&uic4...")
        pyrcc4Label = QLabel("pyrcc4")
        self.pyrcc4Label = QLabel(settings.value("pyrcc4",
                QVariant(PYRCC4)).toString())
        self.pyrcc4Label.setFrameStyle(QFrame.StyledPanel|
                                       QFrame.Sunken)
        pyrcc4Button = QPushButton("p&yrcc4...")
        pylupdate4Label = QLabel("pylupdate4")
        self.pylupdate4Label = QLabel(settings.value("pylupdate4",
                QVariant(PYLUPDATE4)).toString())
        self.pylupdate4Label.setFrameStyle(QFrame.StyledPanel|
                                           QFrame.Sunken)
        pylupdate4Button = QPushButton("&pylupdate4...")
        lreleaseLabel = QLabel("lrelease")
        self.lreleaseLabel = QLabel(settings.value("lrelease",
                QVariant("lrelease")).toString())
        self.lreleaseLabel.setFrameStyle(QFrame.StyledPanel|
                                         QFrame.Sunken)
        lreleaseButton = QPushButton("&lrelease...")
        toolPathGroupBox = QGroupBox("Tool Paths")

        pathsLayout = QGridLayout()
        pathsLayout.addWidget(pyuic4Label, 0, 0)
        pathsLayout.addWidget(self.pyuic4Label, 0, 1)
        pathsLayout.addWidget(pyuic4Button, 0, 2)
        pathsLayout.addWidget(pyrcc4Label, 1, 0)
        pathsLayout.addWidget(self.pyrcc4Label, 1, 1)
        pathsLayout.addWidget(pyrcc4Button, 1, 2)
        pathsLayout.addWidget(pylupdate4Label, 2, 0)
        pathsLayout.addWidget(self.pylupdate4Label, 2, 1)
        pathsLayout.addWidget(pylupdate4Button, 2, 2)
        pathsLayout.addWidget(lreleaseLabel, 3, 0)
        pathsLayout.addWidget(self.lreleaseLabel, 3, 1)
        pathsLayout.addWidget(lreleaseButton, 3, 2)
        toolPathGroupBox.setLayout(pathsLayout)

        resourceModuleNamesGroupBox = QGroupBox(
                "Resource Module Names")
        qrcFiles = bool(int(settings.value("qrc_resources", "1").toString()))
        self.qrcRadioButton = QRadioButton("&qrc_file.py")
        self.qrcRadioButton.setChecked(qrcFiles)
        self.rcRadioButton = QRadioButton("file_&rc.py")
        self.rcRadioButton.setChecked(not qrcFiles)

        radioLayout = QHBoxLayout()
        radioLayout.addWidget(self.qrcRadioButton)
        radioLayout.addWidget(self.rcRadioButton)
        resourceModuleNamesGroupBox.setLayout(radioLayout)

        self.pyuic4xCheckBox = QCheckBox("Run pyuic4 with -&x "
                " to make forms stand-alone runable")
        x = bool(int(settings.value("pyuic4x", "0").toString()))
        self.pyuic4xCheckBox.setChecked(x)

        buttonBox = QDialogButtonBox(QDialogButtonBox.Ok|
                                     QDialogButtonBox.Cancel)

        layout = QVBoxLayout()
        layout.addWidget(toolPathGroupBox)
        layout.addWidget(resourceModuleNamesGroupBox)
        layout.addWidget(self.pyuic4xCheckBox)
        layout.addWidget(buttonBox)
        self.setLayout(layout)

        pyuic4Button.clicked.connect(lambda: self.setPath("pyuic4"))
        pyrcc4Button.clicked.connect(lambda: self.setPath("pyrcc4"))
        pylupdate4Button.clicked.connect(lambda: self.setPath("pylupdate4"))
        lreleaseButton.clicked.connect(lambda: self.setPath("lrelease"))
        buttonBox.accepted.connect(self.accept)
        buttonBox.rejected.connect(self.reject)

        self.setWindowTitle("Make PyQt - Options")

    def accept(self):
        settings = QSettings()
        settings.setValue("pyuic4", QVariant(self.pyuic4Label.text()))
        settings.setValue("pyrcc4", QVariant(self.pyrcc4Label.text()))
        settings.setValue("pylupdate4",
                QVariant(self.pylupdate4Label.text()))
        settings.setValue("lrelease", QVariant(self.lreleaseLabel.text()))
        settings.setValue("qrc_resources",
                "1" if self.qrcRadioButton.isChecked() else "0")
        settings.setValue("pyuic4x",
                "1" if self.pyuic4xCheckBox.isChecked() else "0")
        QDialog.accept(self)

    def setPath(self, tool):
        if tool == "pyuic4":
            label = self.pyuic4Label
        elif tool == "pyrcc4":
            label = self.pyrcc4Label
        elif tool == "pylupdate4":
            label = self.pylupdate4Label
        elif tool == "lrelease":
            label = self.lreleaseLabel
        path = QFileDialog.getOpenFileName(self,
                "Make PyQt - Set Tool Path", label.text())
        if path:
            label.setText(QDir.toNativeSeparators(path))


class Form(QMainWindow):
    def __init__(self):
        super(Form, self).__init__()

        pathLabel = QLabel("Path:")
        settings = QSettings()
        rememberPath = settings.value("rememberpath",
                QVariant(True if Windows else False)).toBool()
        if rememberPath:
            path = (unicode(settings.value("path").toString()) or
                    os.getcwd())
        else:
            path = (sys.argv[1] if len(sys.argv) > 1 and
                    QFile.exists(sys.argv[1]) else os.getcwd())
        self.pathLabel = QLabel(path)
        self.pathLabel.setFrameStyle(QFrame.StyledPanel|
                                     QFrame.Sunken)
        self.pathLabel.setToolTip("The relative path; all actions will "
                "take place here,
and in this path's subdirectories " "if the Recurse checkbox is checked") self.pathButton = QPushButton("&Path...") self.pathButton.setToolTip(self.pathLabel.toolTip().replace( "The", "Sets the")) self.recurseCheckBox = QCheckBox("&Recurse") self.recurseCheckBox.setToolTip("Clean or build all the files " "in the path directory,
and all its subdirectories, " "as deep as they go.") self.transCheckBox = QCheckBox("&Translate") self.transCheckBox.setToolTip("Runs pylupdate4 on all " ".py and .pyw files in conjunction " "with each .ts file.
Then runs " "lrelease on all .ts files to produce " "corresponding .qm files.
The " ".ts files must have been created initially by " "running pylupdate4
directly on a .py " "or .pyw file using the -ts option.") self.debugCheckBox = QCheckBox("&Dry Run") self.debugCheckBox.setToolTip("Shows the actions that would " "take place but does not do them.") self.logBrowser = QTextBrowser() self.logBrowser.setLineWrapMode(QTextEdit.NoWrap) self.buttonBox = QDialogButtonBox() menu = QMenu(self) optionsAction = menu.addAction("&Options...") self.rememberPathAction = menu.addAction("&Remember path") self.rememberPathAction.setCheckable(True) self.rememberPathAction.setChecked(rememberPath) aboutAction = menu.addAction("&About") moreButton = self.buttonBox.addButton("&More", QDialogButtonBox.ActionRole) moreButton.setMenu(menu) moreButton.setToolTip("Use More->Tool paths to set the " "paths to the tools if they are not found by default") self.buildButton = self.buttonBox.addButton("&Build", QDialogButtonBox.ActionRole) self.buildButton.setToolTip("Runs pyuic4 on all " ".ui " "files and pyrcc4 on all .qrc files " "that are out-of-date.
Also runs pylupdate4 " "and lrelease if the Translate checkbox is " "checked.") self.cleanButton = self.buttonBox.addButton("&Clean", QDialogButtonBox.ActionRole) self.cleanButton.setToolTip("Deletes all .py files that " "were generated from .ui and .qrc " "files,
i.e., all files matching qrc_*.py, " "*_rc.py and ui_*.py.") quitButton = self.buttonBox.addButton("&Quit", QDialogButtonBox.RejectRole) topLayout = QHBoxLayout() topLayout.addWidget(pathLabel) topLayout.addWidget(self.pathLabel, 1) topLayout.addWidget(self.pathButton) bottomLayout = QHBoxLayout() bottomLayout.addWidget(self.recurseCheckBox) bottomLayout.addWidget(self.transCheckBox) bottomLayout.addWidget(self.debugCheckBox) bottomLayout.addStretch() bottomLayout.addWidget(self.buttonBox) layout = QVBoxLayout() layout.addLayout(topLayout) layout.addWidget(self.logBrowser) layout.addLayout(bottomLayout) widget = QWidget() widget.setLayout(layout) self.setCentralWidget(widget) aboutAction.triggered.connect(self.about) optionsAction.triggered.connect(self.setOptions) self.pathButton.clicked.connect(self.setPath) self.buildButton.clicked.connect(self.build) self.cleanButton.clicked.connect(self.clean) quitButton.clicked.connect(self.close) self.setWindowTitle("Make PyQt") def closeEvent(self, event): settings = QSettings() settings.setValue("rememberpath", QVariant(self.rememberPathAction.isChecked())) settings.setValue("path", QVariant(self.pathLabel.text())) event.accept() def about(self): QMessageBox.about(self, "关于 Make PyQt", """<b>Make PyQt</b> v {0} <p>版权所有 &copy; 2007-10 Qtrac Ltd. 保留所有权利。 <p>此应用程序可用于构建 PyQt 应用程序。 它根据需要运行 pyuic4、pyrcc4、pylupdate4 和 lrelease, 尽管 pylupdate4 必须直接运行以 创建初始的 .ts 文件。 <p>Python {1} - Qt {2} - PyQt {3} 在 {4} 上运行""".format( __version__, platform.python_version(), QT_VERSION_STR, PYQT_VERSION_STR, platform.system())
def setPath(self): path = QFileDialog.getExistingDirectory(self, "Make PyQt - Set Path", self.pathLabel.text()) if path: self.pathLabel.setText(QDir.toNativeSeparators(path)) def setOptions(self): dlg = OptionsForm(self) dlg.exec_() def build(self): self.updateUi(False) self.logBrowser.clear() recurse = self.recurseCheckBox.isChecked() path = unicode(self.pathLabel.text()) self._apply(recurse, self._build, path) if self.transCheckBox.isChecked(): self._apply(recurse, self._translate, path) self.updateUi(True) def clean(self): self.updateUi(False) self.logBrowser.clear() recurse = self.recurseCheckBox.isChecked() path = unicode(self.pathLabel.text()) self._apply(recurse, self._clean, path) self.updateUi(True) def updateUi(self, enable): for widget in (self.buildButton, self.cleanButton, self.pathButton, self.recurseCheckBox, self.transCheckBox, self.debugCheckBox): widget.setEnabled(enable) if not enable: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) else: QApplication.restoreOverrideCursor() self.buildButton.setFocus() def _apply(self, recurse, function, path): if not recurse: function(path) else: for root, dirs, files in os.walk(path): for dir in sorted(dirs): function(os.path.join(root, dir)) def _make_error_message(self, command, process): err = "" ba = process.readAllStandardError() if not ba.isEmpty(): err = ": " + str(QString(ba)) return "FAILED: %s%s" % (command, err) def _build(self, path): settings = QSettings() pyuic4 = unicode(settings.value("pyuic4", QVariant(PYUIC4)).toString()) pyrcc4 = unicode(settings.value("pyrcc4", QVariant(PYRCC4)).toString()) prefix = unicode(self.pathLabel.text()) pyuic4x = bool(int(settings.value("pyuic4x", "0").toString())) if not prefix.endswith(os.sep): prefix += os.sep failed = 0 process = QProcess() for name in os.listdir(path): source = os.path.join(path, name) target = None if source.endswith(".ui"): target = os.path.join(path, "ui_" + name.replace(".ui", ".py")) command = pyuic4 elif source.endswith(".qrc"): if bool(int(settings.value("qrc_resources", "1").toString())): target = os.path.join(path, "qrc_" + name.replace(".qrc", ".py")) else: target = os.path.join(path, name.replace(".qrc", "_rc.py")) command = pyrcc4 if target is not None: if not os.access(target, os.F_OK) or ( os.stat(source)[stat.ST_MTIME] > os.stat(target)[stat.ST_MTIME]): args = ["-o", target, source] if command == PYUIC4 and pyuic4x: args.insert(0, "-x") if (sys.platform.startswith("darwin") and command == PYUIC4): command = sys.executable args = [PYUIC4] + args msg = ("converted " + source + " to " + target + "") if self.debugCheckBox.isChecked(): msg = "# " + msg + "" else: process.start(command, args) if (not process.waitForFinished(2 * 60 * 1000) or not QFile.exists(target)): msg = self._make_error_message(command, process) failed += 1 self.logBrowser.append(msg.replace(prefix, "")) else: self.logBrowser.append("" "# {0} is up-to-date".format( source.replace(prefix, ""))) QApplication.processEvents() if failed: QMessageBox.information(self, "Make PyQt - Failures", "Try manually setting the paths to the tools " "using More->Options") def _clean(self, path): prefix = unicode(self.pathLabel.text()) if not prefix.endswith(os.sep): prefix += os.sep deletelist = [] for name in os.listdir(path): target = os.path.join(path, name) source = None if (target.endswith(".py") or target.endswith(".pyc") or target.endswith(".pyo")): if name.startswith("ui_") and not name[-1] in "oc": source = os.path.join(path, name[3:-3] + ".ui") elif name.startswith("qrc_"): if target[-1] in "oc": source = os.path.join(path, name[4:-4] + ".qrc") else: source = os.path.join(path, name[4:-3] + ".qrc") elif name.endswith(("_rc.py", "_rc.pyo", "_rc.pyc")): if target[-1] in "oc": source = os.path.join(path, name[:-7] + ".qrc") else: source = os.path.join(path, name[:-6] + ".qrc") elif target[-1] in "oc": source = target[:-1] if source is not None: if os.access(source, os.F_OK): if self.debugCheckBox.isChecked(): self.logBrowser.append("" "# delete {0}".format( target.replace(prefix, ""))) else: deletelist.append(target) else: self.logBrowser.append("" "will not remove " "'{0}' since `{1}' not found" .format(target.replace(prefix, ""), source.replace(prefix, ""))) if not self.debugCheckBox.isChecked(): for target in deletelist: self.logBrowser.append("deleted " "{0}".format( target.replace(prefix, ""))) os.remove(target) QApplication.processEvents() def _translate(self, path): prefix = unicode(self.pathLabel.text()) if not prefix.endswith(os.sep): prefix += os.sep files = [] tsfiles = [] for name in os.listdir(path): if name.endswith((".py", ".pyw")): files.append(os.path.join(path, name)) elif name.endswith(".ts"): tsfiles.append(os.path.join(path, name)) if not tsfiles: return settings = QSettings() pylupdate4 = unicode(settings.value("pylupdate4", QVariant(PYLUPDATE4)).toString()) lrelease = unicode(settings.value("lrelease", QVariant(LRELEASE)).toString()) process = QProcess() failed = 0 for ts in tsfiles: qm = ts[:-3] + ".qm" command1 = pylupdate4 args1 = files + ["-ts", ts] command2 = lrelease args2 = ["-silent", ts, "-qm", qm] msg = "updated {0}".format( ts.replace(prefix, "")) if self.debugCheckBox.isChecked(): msg = "# {0}".format(msg) else: process.start(command1, args1) if not process.waitForFinished(2 * 60 * 1000): msg = self._make_error_message(command1, process) failed += 1 self.logBrowser.append(msg) msg = "generated {0}".format( qm.replace(prefix, "")) if self.debugCheckBox.isChecked(): msg = "# {0}".format(msg) else: process.start(command2, args2) if not process.waitForFinished(2 * 60 * 1000): msg = self._make_error_message(command2, process) failed += 1 self.logBrowser.append(msg) QApplication.processEvents() if failed: QMessageBox.information(self, "Make PyQt - Failures", "Try manually setting the paths to the tools " "using More->Options") app = QApplication(sys.argv) PATH = unicode(app.applicationDirPath()) if Windows: PATH = os.path.join(os.path.dirname(sys.executable), "Lib/site-packages/PyQt4") if os.access(os.path.join(PATH, "bin"), os.R_OK): PATH = os.path.join(PATH, "bin") if sys.platform.startswith("darwin"): i = PATH.find("Resources") if i > -1: PATH = PATH[:i] + "bin" PYUIC4 = os.path.join(PATH, "pyuic4") if sys.platform.startswith("darwin"): PYUIC4 = os.path.dirname(sys.executable) i = PYUIC4.find("Resources") if i > -1: PYUIC4 = PYUIC4[:i] + "Lib/python2.6/site-packages/PyQt4/uic/pyuic.py" PYRCC4 = os.path.join(PATH, "pyrcc4") PYLUPDATE4 = os.path.join(PATH, "pylupdate4") LRELEASE = "lrelease" if Windows: PYUIC4 = PYUIC4.replace("/", "\\") + ".bat" PYRCC4 = PYRCC4.replace("/", "\\") + ".exe" PYLUPDATE4 = PYLUPDATE4.replace("/", "\\") + ".exe" app.setOrganizationName("Qtrac Ltd.") app.setOrganizationDomain("qtrac.eu") app.setApplicationName("Make PyQt") if len(sys.argv) > 1 and sys.argv[1] == "-c": settings = QSettings() settings.setValue("pyuic4", QVariant(PYUIC4)) settings.setValue("pyrcc4", QVariant(PYRCC4)) settings.setValue("pylupdate4", QVariant(PYLUPDATE4)) settings.setValue("lrelease", QVariant(LRELEASE)) form = Form() form.show() app.exec_()
 

 

在 Qt Designer 中创建 GUI 不仅使创建 GUI 更容易,而且还是一个很棒的学习工具。你可以测试一个小部件的外观,查看 Qt 中可用的内容,并查看你可能想要使用的属性。

在使用 PyQt 时,C++ API 文档也是一个非常有用的(可以理解为:必要的)工具。API 转换非常简单,经过一些经验积累,你会发现开发人员的 API 文档是你真正需要的工具之一。在 KDE 中工作时,konqueror 的默认快捷方式是 qt:[widgetname],因此 [alt]+[F2],"qt:qbutton" 会直接带你到正确的 API 文档页面。Trolltech 的文档部分有更多你可能想要查看的文档。

本教程的前 3 个示例是使用 PyQt4 创建的,最后一个示例使用的语法仅适用于 PyQt3。

注意:本页面的先前版本(适用于 pyqt3)可在 http://vizzzion.org/?id=pyqt 找到。

本文档根据 GNU 自由文档许可证发布。

Last modified: Friday, 31 January 2025, 2:24 AM