問題描述
我正在嘗試使用 PyQT5 構建一個簡單的 GUI,有 3 個按鈕用于打開文件瀏覽器,還有一個按鈕用于對所選文件進行處理,但我無法讓我的按鈕連接到執行此操作所需的功能.
I am trying to build a simple GUI using PyQT5, with 3 buttons to open file browsers and one more to run processing with the selected files, but I can't get my buttons to connect to the functions needed to carry this out.
在 Ctrl
類中,_connect_signals
函數似乎沒有調用 _input_select
.誰能幫我弄清楚為什么?
In the Ctrl
class, the _connect_signals
function doesn't seem to be calling _input_select
. Can anyone help me figure out why?
import sys
# Import QApplication and the required widgets from PyQt5.QtWidgets
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.QtWidgets import QWidget
from PyQt5.QtWidgets import QFileDialog
# Create a subclass of QMainWindow to setup the calculator's GUI
class UI(QMainWindow):
"""App's View (GUI)."""
def __init__(self):
"""View initializer."""
super().__init__()
# Set some main window's properties
self.setFixedSize(300, 150)
# Set the central widget and the general layout
self.generalLayout = QVBoxLayout()
self._centralWidget = QWidget(self)
self.setCentralWidget(self._centralWidget)
self._centralWidget.setLayout(self.generalLayout)
# Create the buttons
self._create_buttons()
def _create_buttons(self):
"""Create the buttons."""
self.buttons = {}
buttons_layout = QVBoxLayout()
# Button text | position on the QVBoxLayout
buttons = {
"Select input file...": 0,
"Select config file...": 1,
"Select output file...": 2,
"Run": 3,
}
# Create the buttons and add them to the grid layout
for btnText, pos in buttons.items():
self.buttons[btnText] = QPushButton(btnText)
buttons_layout.addWidget(self.buttons[btnText], pos)
# Add buttons_layout to the general layout
self.generalLayout.addLayout(buttons_layout)
# Create a Controller class to connect the GUI and the model
class Ctrl:
"""App's Controller."""
def __init__(self, setup, view):
"""Controller initializer."""
self._view = view
self._setup = setup
# Connect signals and slots
self._connect_signals()
def _input_select(self): # Not being called
print("input selection")
options = QFileDialog.Options()
file_select, _ = QFileDialog.getOpenFileNames(
self,
'Select Input File...',
'',
'CSV Files (*.csv);;All Files (*)',
options=options
)
if file_select:
self._setup["input"] = file_select
def _connect_signals(self):
"""Connect signals and slots."""
self._view.buttons["Select input file..."].clicked.connect(self._input_select) # Not working!
# Client code
def main():
"""Main function."""
# Create an instance of `QApplication`
app = QApplication(sys.argv)
# Show the app's GUI
view = UI()
view.show()
setup = {}
# Create instance of the controller
Ctrl(setup=setup, view=view)
# Execute app's main loop
sys.exit(app.exec_())
if __name__ == "__main__":
main()
以防萬一,我開始屠殺 這個示例代碼來自一個真正的 Python 教程,但一定是在這個過程中破壞了它.
In case it helps, I started out by butchering this example code from a Real Python tutorial, but must have broken it along the way.
推薦答案
問題是您沒有保留對您正在創建的 Ctrl()
實例的任何持久引用.這會導致 python 垃圾在實例創建后立即收集它.
The problem is that you are not keeping any persistent reference to the Ctrl()
instance you are creating. This results in python garbage collecting it as soon as the instance is created.
要解決這個問題,只需將它分配給一個變量:
To solve the issue, just assign it to a variable:
def main():
"""Main function."""
# Create an instance of `QApplication`
app = QApplication(sys.argv)
# Show the app's GUI
view = UI()
view.show()
setup = {}
# Create instance of the controller
ctrl = Ctrl(setup=setup, view=view)
# Execute app's main loop
sys.exit(app.exec_())
一些注意事項:
- 雖然將邏輯與接口分離通常是一種很好的做法,但它是一個需要謹慎使用的概念,因為有時它只會使事情變得比應有的復雜.大多數時候(尤其是對于簡單的程序),它只會創建更大的代碼庫而沒有帶來任何實際好處:它更難閱讀和調試,并且您可能最終會不斷地從您的邏輯部分和 ui 部分切換代碼;
- 您的代碼顯示了該概念的一個缺點:當您創建文件對話框時,您使用的是
self
,但在這種情況下,它指的是Ctrl
實例,而參數應該是UI
實例(這將導致崩潰,因為 Qt 將獲得意外的參數類型);您可以改用self._view
,但是,如前所述,這種情況下的整個分離只會使事情變得不必要地復雜; - 對引用內部對象的字典鍵使用字符串很少是一個好主意(尤其是在像您這樣使用長描述性字符串時);
- 從一個模塊中導入多個元素時,通常最好將它們分組而不是使用單行導入:它使代碼更整潔,更易于閱讀和檢查:
from PyQt5.QtWidgets import (QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QFileDialog)
- while separating logic from interface is usually good practice, it's a concept that needs to be used with care, as sometimes it only makes things more complex than they should be. Most of the times (especially with simple programs), it only makes a bigger codebase without giving any actual benefit: it's harder to read and to debug, and you'll probably end up continuously switching from the logic parts and the ui parts of your code;
- your code shows one of the drawback of that concept: when you create the file dialog, you're using
self
, but in that case it refers to theCtrl
instance, while the argument should be theUI
instance instead (which will result in a crash, as Qt will get an unexpected argument type); you can useself._view
instead, but, as said, the whole separation in this case just makes things unnecessarily complex; - using strings for dictionary keys that refer to internal objects is rarely a good idea (especially when using long descriptive strings like you did);
- when importing more than one element from a module, it's usually better to group them instead of using single line imports: it makes the code tidier and easier to read and inspect:
from PyQt5.QtWidgets import (QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QFileDialog)
這篇關于PyQt5按鈕未連接的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!