pyqt - 根据用户输入自动更新小部件

pyqt - Automatically update widget on user input

这里是pyqt的新手。当用户 select 在组合框 2 中的某些选项时,尝试自动修改小部件以显示不同的选项。IE 如果用户 selects 'Cliff Erosion' 或 'Dune Erosion',我希望小部件使用其他组合框刷新。同样,如果他们 select 回到 'Rising Tides' 或 'Coastal Flooding' 我希望小部件回到原来的通话。如何刷新小部件?

from PyQt4.QtGui import *


# Create window
class Window(QWidget):

    #This block adds features into the window init
    def __init__(self):
        QWidget.__init__(self)
        self.setWindowTitle('Monterey Bay Sea Level Rise')
        self.resize(300, 240)
        self.addWidgets1()


    def addWidgets1(self):


        #Add drop-down list for selecting forecast year
        self.year_lbl = QLabel("1. Select Forecast Year", self)
        self.year_lbl.move(5,0)
        year = QComboBox(self)
        year.addItem('2030')
        year.addItem('2060')
        year.addItem('2100')
        year.move(5,20)

        #Add drop-down list for selecting hazard
        self.hazard_lbl = QLabel("2. Select Coastal Hazard", self)
        self.hazard_lbl.move(5,50)
        hazard = QComboBox(self)
        hazard.addItem('Rising Tides')
        hazard.addItem('Coastal Storm Flooding')
        hazard.addItem('Cliff Erosion')
        hazard.addItem('Dune Erosion')
        hazard.activated[str].connect(self.addWidget2) 
        hazard.move(5,70)

        #Add drop-down list for inputing model intensity (s1,s2,s3)
        self.intensity_lbl = QLabel("3. Select Intensity", self)
        self.intensity_lbl.move(5,100)
        intensity = QComboBox(self)
        intensity.addItem('Low')
        intensity.addItem('Mid')
        intensity.addItem('High') 
        intensity.move(5,120)


    def addWidget2(self,text):
        #if hazard is cliff erosion or dune erosion we want to update the widget
        #... to include wstorm,long_term AND no_change,stormier

        if text == 'Cliff Erosion' or text == 'Dune Erosion':
            print 'Hi'

            self.type_lbl = QLabel("3. Select type of changes", self)
            self.type_lbl.move(5,150)
            types = QComboBox(self)
            types.addItem('Long-term')
            types.addItem('Storm induced')
            types.move(5,180)

            self.storm_lbl = QLabel("4. Select for stormier", self)
            self.storm_lbl.move(5,150)
            storm = QComboBox(self)
            storm.addItem('No Change')
            storm.addItem('Stormier')
            storm.move(5,180)       


if __name__ == '__main__':

    import sys
    app = QApplication(sys.argv)
    window = Window()
    #window.resize(100, 60)
    window.show()

    sys.exit(app.exec_())

向 Qt 应用程序添加小部件的常规方法是使用 layouts。他们将计算您的小部件的首选大小和位置,并在需要时更新它,例如添加小部件或调整 window 大小时(请注意在执行期间将 window 变小并与我下面的解决方案进行比较时会发生什么)。我确信可以自己完成所有移动和调整大小,但 QLayouts 确实是可行的方法,我强烈建议您也使用它们。

QLayout 有几种类型,但在您的情况下我会使用 QFormLayout。令我惊讶的是,QFormLayout 确实有一个 addRow 方法,但没有对应的 removeRow。但是,我发现仅 showing/hiding 组合框在需要时也能达到目的。我在下面改编了你的例子。

最后,即使只显示或隐藏最后两个组合框也会导致布局稍微移动前三个。这是因为第 4 个标签是所有标签中最长的。我觉得这很烦人。也许更好的解决方案是在需要时 enable/disable 组合框。这样做的额外好处是向用户表明这些选项甚至存在。另请参见下面的代码。第二种选择可能是使用 QGridLayout(而不是 QFormLayout)并使用 setColumnMinimumWidth 将第一列设置为可以容纳所有可能标签的大小。

from PyQt4 import QtGui 

# Create window
class Window(QtGui.QWidget):

    #This block adds features into the window init
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.setWindowTitle('Monterey Bay Sea Level Rise')
        self.resize(300, 240)
        self.addWidgets1()

    def addWidgets1(self):

        self.layout = QtGui.QFormLayout()
        self.setLayout(self.layout)

        #Add drop-down list for selecting forecast year

        # You don't need to set to parent of the widgets to self anymore, the
        # layout will set the parent automatically when you add the widgets
        self.year_lbl = QtGui.QLabel("1. Select Forecast Year")
        # self.year_lbl.move(5,0) # Can be removed. The layout takes care of it.
        year = QtGui.QComboBox()
        year.addItem('2030')
        year.addItem('2060')
        year.addItem('2100')
        self.layout.addRow(self.year_lbl, year)        

        #Add drop-down list for selecting hazard
        self.hazard_lbl = QtGui.QLabel("2. Select Coastal Hazard")
        self.hazard = QtGui.QComboBox()
        self.hazard.addItem('Rising Tides')
        self.hazard.addItem('Coastal Storm Flooding')
        self.hazard.addItem('Cliff Erosion')
        self.hazard.addItem('Dune Erosion')
        self.hazard.activated[str].connect(self.updateComboboxes) 
        self.layout.addRow(self.hazard_lbl, self.hazard)        

        #Add drop-down list for inputing model intensity (s1,s2,s3)
        self.intensity_lbl = QtGui.QLabel("3. Select Intensity")
        intensity = QtGui.QComboBox()
        intensity.addItem('Low')
        intensity.addItem('Mid')
        intensity.addItem('High') 
        self.layout.addRow(self.intensity_lbl, intensity)        

        self.types_lbl = QtGui.QLabel("3. Select type of changes")
        self.types = QtGui.QComboBox()
        self.types.addItem('Long-term')
        self.types.addItem('Storm induced')
        self.layout.addRow(self.types_lbl, self.types)        

        self.storm_lbl = QtGui.QLabel("4. Select for stormier")
        self.storm = QtGui.QComboBox()
        self.storm.addItem('No Change')
        self.storm.addItem('Stormier')
        self.layout.addRow(self.storm_lbl, self.storm)        

        # show initial state
        self.updateComboboxes() 


    def updateComboboxes(self, text=None):
        #if hazard is cliff erosion or dune erosion we want to update the widget
        #... to include wstorm,long_term AND no_change,stormier

        if text is None:
            text = self.hazard.currentText()

        usable = (text == 'Cliff Erosion' or text == 'Dune Erosion')

        if True: # change to False to use enabling/disabling widgets
            # May cause other widgets to be relocated
            self.types_lbl.setVisible(usable)
            self.types.setVisible(usable)
            self.storm_lbl.setVisible(usable)
            self.storm.setVisible(usable)
        else:
            # This option doesn't relocate widgets
            # Also may give additional clue to the uses that this exsits
            self.types_lbl.setEnabled(usable)
            self.types.setEnabled(usable)
            self.storm_lbl.setEnabled(usable)
            self.storm.setEnabled(usable)

if __name__ == '__main__':
    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window()
    #window.resize(100, 60)
    window.show()
    sys.exit(app.exec_())