首页 > 解决方案 > 调用方法和调整按钮文本

问题描述

我正在尝试结合 PyQt5 和 Qt Designer 制作一个膳食调度程序(最终这将从数据库中生成一个购物清单)。膳食计划是一个由 7 x 3 个按钮组成的网格(7 天,每天 3 顿饭)——总共 21 个按钮。

当用户单击膳食计划中的按钮(“SelMealButtons”之一)时,会打开一个弹出窗口,其中包含可供选择的膳食列表(这是代码中的 Selector 类)。用户选择一餐并使用“OK”按钮(以下代码中的“pushButton”)确认他们的选择。

我试图通过“set_button_labels”方法让餐点名称作为相应的按钮文本显示在餐点计划中。为简单起见,示例代码中仅引用了 21 个“SelMealButtons”中的三个,如下所示:

import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtGui import QIcon
from PyQt5 import uic
from PyQt5 import QtCore
from PyQt5.QtCore import pyqtSignal, pyqtSlot

uifile_1 = 'untitled3.ui'
form_1, base_1 = uic.loadUiType(uifile_1)

uifile_2 = 'untitled2.ui'
form_2, base_2 = uic.loadUiType(uifile_2)

array = ["Meal 1", "Meal 2", "Meal 3"]
meal_schedule = [""]*21

class Schedule(base_1, form_1):

    def __init__(self):
        super(base_1,self).__init__()
        self.setupUi(self)

        self.SelMealButton.clicked.connect(lambda: self.m_b_pressed(0))
        self.SelMealButton_2.clicked.connect(lambda: self.m_b_pressed(1))
        self.SelMealButton_3.clicked.connect(lambda: self.m_b_pressed(2))

    def m_b_pressed(self, button_no):
        self.selector = Selector()
        self.selector.show()
        self.selector.pushButton.clicked.connect(lambda: self.selector.OKbutton(button_no))

    def set_button_labels(self, message):
        print(message)
        self.SelMealButton.setText(meal_schedule[0])
        self.SelMealButton_2.setText(meal_schedule[1])
        self.SelMealButton_3.setText(meal_schedule[2])

class Selector(base_2, form_2):

    def __init__(self):
        super(base_2, self).__init__()
        self.setupUi(self)

        for item in array:
            self.listWidget.addItem(item)

        self.pushButton_2.clicked.connect(self.closewindow)

    def closewindow(self):
        self.close()
        self.schedule = Schedule()

    def OKbutton(self, button_no):
         x = self.listWidget.currentRow()
         y = str(array[x])
         meal_schedule[button_no] = y
         self.schedule = Schedule()
         self.schedule.set_button_labels(y)
         self.close()

 if __name__ == '__main__':
     app = QApplication(sys.argv)
     s = Schedule()
     s.show()
     sys.exit(app.exec_())

用户界面文件如下:

无标题3.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>234</width>
    <height>339</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QPushButton" name="SelMealButton">
    <property name="geometry">
     <rect>
      <x>70</x>
      <y>60</y>
      <width>131</width>
      <height>51</height>
     </rect>
    </property>
    <property name="text">
     <string/>
    </property>
   </widget>
   <widget class="QLabel" name="MealtimeLabel">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>80</y>
      <width>51</width>
      <height>16</height>
     </rect>
    </property>
    <property name="text">
     <string>Breakfast</string>
    </property>
   </widget>
   <widget class="QLabel" name="label">
    <property name="geometry">
     <rect>
      <x>120</x>
      <y>40</y>
      <width>21</width>
      <height>16</height>
     </rect>
    </property>
    <property name="text">
     <string>Mon</string>
    </property>
   </widget>
   <widget class="QPushButton" name="SelMealButton_2">
    <property name="geometry">
     <rect>
      <x>70</x>
      <y>120</y>
      <width>131</width>
      <height>51</height>
     </rect>
    </property>
    <property name="text">
     <string/>
    </property>
   </widget>
   <widget class="QPushButton" name="SelMealButton_3">
    <property name="geometry">
     <rect>
      <x>70</x>
      <y>180</y>
      <width>131</width>
      <height>51</height>
     </rect>
    </property>
    <property name="text">
     <string/>
    </property>
   </widget>
   <widget class="QLabel" name="label_2">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>140</y>
      <width>47</width>
      <height>13</height>
     </rect>
    </property>
    <property name="text">
     <string>Lunch</string>
    </property>
   </widget>
   <widget class="QLabel" name="label_3">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>200</y>
      <width>47</width>
      <height>13</height>
     </rect>
    </property>
    <property name="text">
     <string>Dinner</string>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>234</width>
     <height>21</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

untitled2.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Dialog</class>
 <widget class="QDialog" name="Dialog">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Dialog</string>
  </property>
  <widget class="QListWidget" name="listWidget">
   <property name="geometry">
    <rect>
     <x>10</x>
     <y>10</y>
     <width>256</width>
     <height>281</height>
    </rect>
   </property>
  </widget>
  <widget class="QPushButton" name="pushButton">
   <property name="geometry">
    <rect>
     <x>290</x>
     <y>20</y>
     <width>75</width>
     <height>23</height>
    </rect>
   </property>
   <property name="text">
    <string>OK</string>
   </property>
  </widget>
  <widget class="QPushButton" name="pushButton_2">
   <property name="geometry">
    <rect>
     <x>290</x>
     <y>60</y>
     <width>75</width>
     <height>23</height>
    </rect>
   </property>
   <property name="text">
    <string>Cancel</string>
   </property>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

只要从“Selector”类调用“OKbutton”方法,它就可以将listWidget 值分配给meal_schedule 数组。我知道(通过测试)这个方法反过来又在 Schedule 类中调用“set_button_labels”方法。但是,“set_button_labels”方法不会根据需要调整 SelMealButtons 的文本***。是否有人能够就为什么会这样和/或我如何实现此功能提出任何建议?

我已经开始阅读有关插槽和信号的内容,但很难理解它。

***(解决此问题的一种方法是在调用 Selector 小部件时关闭 Schedule 窗口 - 然后在 Selector 小部件关闭时再次打开它。但是我更愿意保持 Schedule 窗口保持打开状态。)

标签: pythonpyqtpyqt5

解决方案


问题是,每次调用时,OKbutton您都在创建一个新实例,并且在Schedule实例上设置按钮文本,而不是主实例。此外,该实例从未实际显示(同样发生在 中)。close_window()

您需要做的是跟踪当前按钮并连接到选择器的“ok”按钮,以便正确更新值。以下是您的示例的可能重新实现:

array = ["Meal 1", "Meal 2", "Meal 3"]
days = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"]
# a simple example of meals "array" with the format "day meal"
meal_schedule = ["{} {}".format(d, m) for d in days for m in array]

class Schedule(base_1, form_1):
    def __init__(self):
        super(base_1,self).__init__()
        self.setupUi(self)

        self.SelMealButton.clicked.connect(lambda: self.m_b_pressed(0))
        self.SelMealButton_2.clicked.connect(lambda: self.m_b_pressed(1))
        self.SelMealButton_3.clicked.connect(lambda: self.m_b_pressed(2))

        self.selector = Selector()
        self.selector.pushButton.clicked.connect(self.set_button_labels)

        self.buttons = (
            self.SelMealButton, 
            self.SelMealButton_2, 
            self.SelMealButton_3
        )

        # example, wednesday
        self.current_day = 2

    def m_b_pressed(self, button_no):
        self.current_meal_button = self.buttons[button_no]
        self.selector.show()

    def set_button_labels(self):
        index = self.selector.listWidget.currentRow() + self.current_day * 3
        meal = meal_schedule[index]
        self.current_meal_button.setText(meal)


class Selector(base_2, form_2):
    def __init__(self):
        super(base_2, self).__init__()
        self.setupUi(self)

        for item in array:
            self.listWidget.addItem(item)

        self.pushButton_2.clicked.connect(self.close)
        self.pushButton.clicked.connect(self.close)

请注意,您的实现有两个重要问题。

  1. Selector 窗口可能应该是一个模式对话框,它会阻止与其他窗口的交互,直到它关闭:使用您当前的代码,用户可以在显示 Selector 时在 Schedule 中选择不同的餐点,这会使事情变得非常混乱。在 Designer 中创建一个新对话框(已定义按钮的两个对话框之一),然后使用以下命令调用它exec_
class Schedule(base_1, form_1):
    def __init__(self):
        super(base_1,self).__init__()
        self.setupUi(self)

        self.SelMealButton.clicked.connect(lambda: self.m_b_pressed(0))
        self.SelMealButton_2.clicked.connect(lambda: self.m_b_pressed(1))
        self.SelMealButton_3.clicked.connect(lambda: self.m_b_pressed(2))

        # not needed anymore
        # self.selector = Selector()
        # self.selector.pushButton.clicked.connect(self.set_button_labels)

        self.buttons = (
            self.SelMealButton, 
            self.SelMealButton_2, 
            self.SelMealButton_3
        )
        self.current_day = 2

    def m_b_pressed(self, button_no):
        selector = Selector(self)
        if selector.exec_():
            index = selector.listWidget.currentRow() + self.current_day * 3
            meal = meal_schedule[index]
            self.buttons[button_no].setText(meal)


class Selector(base_2, form_2):
    def __init__(self):
        super(base_2, self).__init__()
        self.setupUi(self)

        for item in array:
            self.listWidget.addItem(item)
  1. 即使它与手头的问题无关,通常也不鼓励使用固定的几何图形,而应始终使用布局管理器。一个简单的原因是我能够缩小两个窗口,并且在一定尺寸以下界面变得无法使用。

推荐阅读