警告

本节包含从C++自动翻译成Python的代码片段,可能包含错误。

旋转框示例#

旋转框示例展示了如何在Qt中使用多种不同类型的旋转框,从简单的QSpinBox小部件到一个更复杂的编辑器,如QDateTimeEdit小部件。

../_images/spinboxes-example.png

示例由一个用于显示Qt中可用的不同旋转框小部件的单一Window类组成。

窗口类定义#

Window类继承自QWidget,包含用于提供交互功能的两个槽

class Window(QWidget):

    Q_OBJECT
# public
    Window(QWidget parent = None)
# public slots
    def changePrecision(decimals):
    def setFormatString(formatString):
# private
    def createSpinBoxes():
    def createDateTimeEdits():
    def createDoubleSpinBoxes():
    meetingEdit = QDateTimeEdit()
    doubleSpinBox = QDoubleSpinBox()
    priceSpinBox = QDoubleSpinBox()
    scaleSpinBox = QDoubleSpinBox()
    spinBoxesGroup = QGroupBox()
    editsGroup = QGroupBox()
    doubleSpinBoxesGroup = QGroupBox()
    meetingLabel = QLabel()
    groupSeparatorSpinBox = QSpinBox()
    groupSeparatorSpinBox_d = QDoubleSpinBox()

私有函数用于设置窗口中每种类型的旋转框。我们使用成员变量来跟踪各种小部件,以便在有需要时重新配置它们。

窗口类实现#

构造函数仅调用私有函数来设置示例中使用的不同类型的旋转框,并将每个组放置在布局中

def __init__(self, parent):
    super().__init__(parent)

    createSpinBoxes()
    createDateTimeEdits()
    createDoubleSpinBoxes()
    layout = QHBoxLayout()
    layout.addWidget(spinBoxesGroup)
    layout.addWidget(editsGroup)
    layout.addWidget(doubleSpinBoxesGroup)
    setLayout(layout)
    setWindowTitle(tr("Spin Boxes"))

我们使用布局来管理窗口子小部件的排列,并更改窗口标题。

createSpinBoxes()函数构建一个QGroupBox并将三个带有描述性标签的QSpinBox小部件放置在内,以表示它们所期望的输入类型。

def createSpinBoxes(self):

    spinBoxesGroup = QGroupBox(tr("Spinboxes"))
    integerLabel = QLabel(tr("Enter a value between "()
        "%1 and %2:").arg(-20).arg(20))
    integerSpinBox = QSpinBox()
    integerSpinBox.setRange(-20, 20)
    integerSpinBox.setSingleStep(1)
    integerSpinBox.setValue(0)

第一个旋转框展示了使用QSpinBox的最简单方法。它接受从-20到20的值,当前值可以通过箭头按钮或上下键增加或减少1,默认值为0。

第二个旋转框使用了更大的步长,并显示后缀以提供有关数字表示的数据类型的更多信息

zoomLabel = QLabel(tr("Enter a zoom value between "()
    "%1 and %2:").arg(0).arg(1000))
zoomSpinBox = QSpinBox()
zoomSpinBox.setRange(0, 1000)
zoomSpinBox.setSingleStep(10)
zoomSpinBox.setSuffix("%")
zoomSpinBox.setSpecialValueText(tr("Automatic"))
zoomSpinBox.setValue(100)

此旋转框也显示了一个特殊的值而不是它定义的最小值。这意味着它永远不会显示0%,而是当选择最小值时显示“自动”。

第三个旋转框展示了如何使用前缀

priceLabel = QLabel(tr("Enter a price between "()
    "%1 and %2:").arg(0).arg(999))
priceSpinBox = QSpinBox()
priceSpinBox.setRange(0, 999)
priceSpinBox.setSingleStep(1)
priceSpinBox.setPrefix("$")
priceSpinBox.setValue(99)

为了简化,我们展示了一个带有前缀但没有后缀的旋转框。同时也可以同时使用两者。

groupSeparatorSpinBox = QSpinBox()
groupSeparatorSpinBox.setRange(-99999999, 99999999)
groupSeparatorSpinBox.setValue(1000)
groupSeparatorSpinBox.setGroupSeparatorShown(True)
groupSeparatorChkBox = QCheckBox()
groupSeparatorChkBox.setText(tr("Show group separator"))
groupSeparatorChkBox.setChecked(True)
groupSeparatorChkBox.toggled.connect(groupSeparatorSpinBox,
        QSpinBox.setGroupSeparatorShown)
hexLabel = QLabel(tr("Enter a value between "()
    "%1 and %2:").arg('-' + QString.number(31, 16)).arg(QString.number(31, 16)))
hexSpinBox = QSpinBox()
hexSpinBox.setRange(-31, 31)
hexSpinBox.setSingleStep(1)
hexSpinBox.setValue(0)
hexSpinBox.setDisplayIntegerBase(16)
spinBoxLayout = QVBoxLayout()
spinBoxLayout.addWidget(integerLabel)
spinBoxLayout.addWidget(integerSpinBox)
spinBoxLayout.addWidget(zoomLabel)
spinBoxLayout.addWidget(zoomSpinBox)
spinBoxLayout.addWidget(priceLabel)
spinBoxLayout.addWidget(priceSpinBox)
spinBoxLayout.addWidget(hexLabel)
spinBoxLayout.addWidget(hexSpinBox)
spinBoxLayout.addWidget(groupSeparatorChkBox)
spinBoxLayout.addWidget(groupSeparatorSpinBox)
spinBoxesGroup.setLayout(spinBoxLayout)

函数的其余部分设置组框的布局,并将每个小部件放置在内。

函数 createDateTimeEdits() 构建了一个带选择框的另一个分组框,用于编辑日期和时间。

def createDateTimeEdits(self):

    editsGroup = QGroupBox(tr("Date and time spin boxes"))
    dateLabel = QLabel()
    dateEdit = QDateEdit(QDate.currentDate())
    dateEdit.setDateRange(QDate(2005, 1, 1), QDate(2010, 12, 31))
    dateLabel.setText(tr("Appointment date (between %0 and %1):")
                       .arg(dateEdit.minimumDate().toString(Qt.ISODate))
                       .arg(dateEdit.maximumDate().toString(Qt.ISODate)))

第一个选择框是一个 QDateEdit 小部件,可以接受使用 QDate 值指定的给定范围内的日期。当光标处于相关部分时,可以使用箭头按钮和上下键来增加和减少年、月和日的值。

第二个选择框是一个 QTimeEdit 小部件

timeLabel = QLabel()
timeEdit = QTimeEdit(QTime.currentTime())
timeEdit.setTimeRange(QTime(9, 0, 0, 0), QTime(16, 30, 0, 0))
timeLabel.setText(tr("Appointment time (between %0 and %1):")
                   .arg(timeEdit.minimumTime().toString(Qt.ISODate))
                   .arg(timeEdit.maximumTime().toString(Qt.ISODate)))

时间允许的值使用 QTime 值定义。

第三个选择框是一个 QDateTimeEdit 小部件,可以显示日期和时间值,我们在其上方放置一个标签以指示会议允许的时间范围。这些小部件会在用户更改格式字符串时更新。

meetingLabel = QLabel()
meetingEdit = QDateTimeEdit(QDateTime.currentDateTime())

日期时间编辑器使用的格式字符串,同样也显示在标签的字符串中,是从组合框中的一组字符串中选择的

formatLabel = QLabel(tr("Format string for the meeting date "()
                                    "and time:"))
formatComboBox = QComboBox()
formatComboBox.addItem("yyyy-MM-dd hh:mm:ss (zzz 'ms')")
formatComboBox.addItem("hh:mm:ss MM/dd/yyyy")
formatComboBox.addItem("hh:mm:ss dd/MM/yyyy")
formatComboBox.addItem("hh:mm:ss")
formatComboBox.addItem("hh:mm ap")

formatComboBox.textActivated.connect(
        self.setFormatString)

来自此组合框的信号连接到 Window 类(稍后显示)中的槽。

editsLayout = QVBoxLayout()
editsLayout.addWidget(dateLabel)
editsLayout.addWidget(dateEdit)
editsLayout.addWidget(timeLabel)
editsLayout.addWidget(timeEdit)
editsLayout.addWidget(meetingLabel)
editsLayout.addWidget(meetingEdit)
editsLayout.addWidget(formatLabel)
editsLayout.addWidget(formatComboBox)
editsGroup.setLayout(editsLayout)

分组框中的每个子小部件都放置在布局中。

每当用户在组合框中选择新的格式字符串时,都会调用 setFormatString() 槽。使用信号传递的原始字符串设置 QDateTimeEdit 小部件的显示格式

def setFormatString(self, formatString):

    meetingEdit.setDisplayFormat(formatString)

根据可见的部分,我们设置一个新的日期或时间范围,并更新相关的标签,以提供用户相关的信息

if meetingEdit.displayedSections()  QDateTimeEdit.DateSections_Mask:
    meetingEdit.setDateRange(QDate(2004, 11, 1), QDate(2005, 11, 30))
    meetingLabel.setText(tr("Meeting date (between %0 and %1):")
        .arg(meetingEdit.minimumDate().toString(Qt.ISODate))
        .arg(meetingEdit.maximumDate().toString(Qt.ISODate)))
else:
    meetingEdit.setTimeRange(QTime(0, 7, 20, 0), QTime(21, 0, 0, 0))
    meetingLabel.setText(tr("Meeting time (between %0 and %1):")
        .arg(meetingEdit.minimumTime().toString(Qt.ISODate))
        .arg(meetingEdit.maximumTime().toString(Qt.ISODate)))

当格式字符串更改时,将会有适当的标签和日期、时间或两种类型的输入的小部件。

函数 createDoubleSpinBoxes() 构建了三个用于输入双精度浮点数的选取框

def createDoubleSpinBoxes(self):

    doubleSpinBoxesGroup = QGroupBox(tr("Double precision spinboxes"))
    precisionLabel = QLabel(tr("Number of decimal places "()
                                           "to show:"))
    precisionSpinBox = QSpinBox()
    precisionSpinBox.setRange(0, 100)
    precisionSpinBox.setValue(2)

在构建 QDoubleSpinBox 小部件之前,我们创建了一个选择框来控制它们显示的小数位数。默认情况下,以下选取框中只显示两位小数,每个都相当于由函数 createSpinBoxes() 创建的分组中的选取框。

第一个双精度选取框显示了一个基本的双精度选取框,其范围、步长和默认值与 createSpinBoxes() 函数中的第一个选取框相同

doubleLabel = QLabel(tr("Enter a value between "()
    "%1 and %2:").arg(-20).arg(20))
doubleSpinBox = QDoubleSpinBox()
doubleSpinBox.setRange(-20.0, 20.0)
doubleSpinBox.setSingleStep(1.0)
doubleSpinBox.setValue(0.0)

但是,此选取框也允许输入非整数值。

第二个选取框显示一个后缀,并显示一个特殊值而不是最小值

scaleLabel = QLabel(tr("Enter a scale factor between "()
    "%1 and %2:").arg(0).arg(1000.0))
scaleSpinBox = QDoubleSpinBox()
scaleSpinBox.setRange(0.0, 1000.0)
scaleSpinBox.setSingleStep(10.0)
scaleSpinBox.setSuffix("%")
scaleSpinBox.setSpecialValueText(tr("No scaling"))
scaleSpinBox.setValue(100.0)

第三个选取框显示一个前缀而不是后缀

priceLabel = QLabel(tr("Enter a price between "()
    "%1 and %2:").arg(0).arg(1000))
priceSpinBox = QDoubleSpinBox()
priceSpinBox.setRange(0.0, 1000.0)
priceSpinBox.setSingleStep(1.0)
priceSpinBox.setPrefix("$")
priceSpinBox.setValue(99.99)
precisionSpinBox.valueChanged.connect(

我们将指定精度的 QSpinBox 小部件连接到 Window 类的槽。

spinBoxLayout = QVBoxLayout()
spinBoxLayout.addWidget(precisionLabel)
spinBoxLayout.addWidget(precisionSpinBox)
spinBoxLayout.addWidget(doubleLabel)
spinBoxLayout.addWidget(doubleSpinBox)
spinBoxLayout.addWidget(scaleLabel)
spinBoxLayout.addWidget(scaleSpinBox)
spinBoxLayout.addWidget(priceLabel)
spinBoxLayout.addWidget(priceSpinBox)
spinBoxLayout.addWidget(groupSeparatorChkBox)
spinBoxLayout.addWidget(groupSeparatorSpinBox_d)
doubleSpinBoxesGroup.setLayout(spinBoxLayout)

函数其余部分将每个小部件放置在一个用于组框的布局中。

当用户更改精度微调框中的值时,将调用 changePrecision() 槽。

def changePrecision(self, decimals):

    doubleSpinBox.setDecimals(decimals)
    scaleSpinBox.setDecimals(decimals)
    priceSpinBox.setDecimals(decimals)

此函数仅使用由信号提供的整数来指定每个 QDoubleSpinBox 小部件的十进制位数。每当它们的 decimals 属性更改时,这些将会自动更新。

示例项目 @ code.qt.io