2016-07-15 3 views
1

QtDesigner (SourceForm, DestinationForm)에 두 개의 창을 작성하고 pyuic5를 사용하여 .ui 페이지를 변환했습니다. 누적 위젯을 사용하여 두 창 사이를 탐색하는 방법으로 세 번째 클래스 WController을 사용하고 있습니다. 어떤 데이터로 treeWidget을 채우는 SourceForm 버튼이 있고 handle_treewidget_itemchange 메서드는 의 특정 항목이 self.treeWidget.itemChanged.connect(self.handle_treewidget_itemchange)을 사용하여 선택되거나 선택 취소되면 어떻게되는지를 나타냅니다.PyQt5 초보자 - 신호 및 누락 된 위치 인수

TypeError: handle_treewidget_itemchange() missing 2 required positional arguments: 'row' and 'col'

내가 꺼내 경우 그것은 itemChanged.connect 자동으로 슬롯으로 변경되었지만 handle_treewidget_itemchange(self,row,col)가 처음으로 호출 될 때, 내 스크립트가 형식 오류와 충돌이 있었는지의 행과 열을 보내는 것이 나의 이해했다 rowcol args이면 스크립트가 정상적으로 실행됩니다. 원래 두 메서드와 호출을 SourceForm .py 파일 자체에 넣었을 때 코드가 의도 한대로 작동했습니다 ... 아마도 이것은 범위 문제일까요? 사용하는 경우

from PyQt5 import QtCore, QtWidgets 
from PyQt5.QtCore import pyqtSlot 
from imp_sourceform import Ui_SourceForm 
from imp_destform import Ui_DestinationForm 


class WController(QtWidgets.QMainWindow): 
    def __init__(self, parent=None): 
     super(WController, self).__init__(parent) 
     self.central_widget = QtWidgets.QStackedWidget() 
     self.setCentralWidget(self.central_widget) 

     self.sourcewindow = SourceForm() 
     self.destinationwindow = DestinationForm() 

     self.central_widget.addWidget(self.sourcewindow) 
     self.central_widget.addWidget(self.destinationwindow) 

     self.central_widget.setCurrentWidget(self.sourcewindow) 

     self.sourcewindow.selectdestinationsbutton.clicked.connect(lambda: self.navigation_control(1)) 
     self.destinationwindow.backbutton.clicked.connect(lambda: self.navigation_control(0)) 

    def navigation_control(self, topage): 
     if topage == 1: 
      self.central_widget.setCurrentWidget(self.destinationwindow) 
     elif topage == 0: 
      self.central_widget.setCurrentWidget(self.sourcewindow) 

class SourceForm(QtWidgets.QWidget, Ui_SourceForm): 
    def __init__(self): 
     super(SourceForm, self).__init__() 
     self.setupUi(self) 

     self.treeWidget.itemChanged.connect(self.handle_treewidget_itemchange) 

    @pyqtSlot() 
    def handle_treewidget_itemchange(self,row,col): 
     if row.parent() is None and row.checkState(col) == QtCore.Qt.Unchecked: 
      for x in range(0,row.childCount()): 
       row.child(x).setCheckState(0, QtCore.Qt.Unchecked) 
     elif row.parent() is None and row.checkState(col) == QtCore.Qt.Checked: 
      for x in range(0,row.childCount()): 
       row.child(x).setCheckState(0, QtCore.Qt.Checked) 
     else: 
      pass 

class DestinationForm(QtWidgets.QWidget, Ui_DestinationForm): 
    def __init__(self): 
     super(DestinationForm, self).__init__() 
     self.setupUi(self) 

if __name__ == '__main__': 
    import sys 
    app = QtWidgets.QApplication(sys.argv) 
    window = WController() 
    window.show() 
    sys.exit(app.exec_()) 

답변

-1

당신은주의해야합니다 : 파이썬 여전히 동안 나쁜 생각 :(

나는 필수 아래 코드를 제거하기 위해 노력했습니다를 PyQt는을 경험 사용하려고 생각하기 시작하고 pyqtSlot은 꾸미고있는 슬롯의 서명을 너무 쉽게 끊기 때문에, 슬롯에 인수가없는 것으로 다시 정의하여 오류 메시지가 나타나는 이유를 설명합니다. 귀하의 예가 그것 없이는 완벽하게 잘 작동하므로 간단하게 제거하십시오.의 주 목적은 서로 다른 서명을 가진 슬롯의 여러 가지 서로 다른 오버로드를 정의 할 수 있습니다. 크로스 스레드 연결을 만들 때 가끔 필요할 수도 있습니다. 그러나 이러한 유스 케이스는 비교적 드물며 대부분의 PyQt/PySide 애플리케이션에서는 pyqtSlot을 전혀 사용할 필요가 없습니다. 신호는 파이썬 호출 가능 객체에 연결할 수 있습니다.이 객체는 슬롯으로 꾸며 졌든 그렇지 않든 상관 없습니다.

+0

pyqtSlot 실제 Qt는 슬롯을 만듭니다

는 하나 개의 연결 또는 기타를 활성화 할 수 있습니다,이 코드를 참조하고, 윈도우가 가비지 수집 여부가 될 수 있는지 여부를 보여줍니다 행동의 차이를 관찰 슬롯이있는 QObject가 파괴되거나 가비지 수집 될 때 연결이 끊어집니다 (Qt는 삭제 된 QObject에서 연결을 끊습니다). 내가 틀렸다고 정정하되'@ pyqtSlot'을 사용하지 않는다면 연결은 QObject를 추적 할 수 없으므로 호출 가능 객체에 대한 참조를 유지하고 QObject에 대한 참조를 유지하여 파괴. IMHO 가능할 때마다'@ pyqtSlot'을 사용하는 것이 더 좋습니다 –

+0

오 세상에, 당황 스럽네요, 지금 작동 중입니다! 정말 고맙습니다! '@pyqtSlot()'데코레이터를 사용하고 있었기 때문에 슬롯을 쉽게 찾을 수있었습니다. 나는 (위험하게) 그 형태로 양성이라고 생각했다. 원래'handle_treewidget_itemchange' 메서드와 그것의 connect 문을'SourceForm'에 넣었습니다. (일단 GUI를 조정하기를 원했을 때 나는 빨리 배웠습니다.) 슬롯은 행과 열의 인수를'pyqtslot '데코레이터 그대로 ... 그래서 나는 결코 그것을 잠재적 인 문제 해결로 생각하지 않았습니다. –

+0

저는 방금 말한 것을 테스트했습니다 : 실제 슬롯에 연결하는 http://pastebin.com/W5tFkWGL은 "호출 가능"슬롯을 사용하는 것과 달리 참조 계산을 방해하지 않습니다. 그래서, 나는 "모든 호출 가능"을'connect '에 대한 타겟으로 사용하는 것은 나쁜 아이디어라고 생각합니다. 가능한 한 피해야하며, pyqtSlot으로 바꾸어야합니다. –

0

이미이 질문에 대한 대답은 받아 들여지지 만 어쨌든 나는 내 것을 제공 할 것입니다.

문제가있는 슬롯이 itemChanged(QTreeWidgetItem *item, int column) 신호에 연결되어 있으므로 pyqtSlot@pyqtSlot(QTreeWidgetItem, int)과 같아야합니다.

이제 ekhumoro이 지적했듯이, PyQt는 __call__ 메소드를 가진 메소드, 람다 또는 펑터 중 하나 인 파이썬 호출 가능 객체에 신호를 연결하도록 허용합니다. 그러나 @pyqtSlot을 사용하는 것보다는 덜 안전합니다.

예를 들어, 소스 QObject (신호를 내 보낸 사람)가 파괴되거나 대상 QObject (Qt 슬롯이있는)가 파괴되면 Qt는 자동으로 연결을 끊습니다. 예를 들어 위젯을 제거한 경우 다른 곳에서 발생한 문제가 있음을 알릴 필요가 없습니다. @pyqtSlot을 사용하면 클래스에 실제 Qt 슬롯이 만들어 지므로이 연결 해제 메커니즘이 적용될 수 있습니다. 또한 Qt는 대상 QObject에 대한 강력한 참조를 보유하지 않으므로 삭제할 수 있습니다.

호출 가능 객체 (예 : 데코 레이팅되지 않은 바운드 메소드)를 사용하는 경우 Qt는 연결의 대상 QObject를 식별 할 방법이 없습니다. 더 나쁜 것은 파이썬 호출 가능 객체를 넘기므로 강력한 참조를 보유 할 것이고 호출 가능 객체 (바운드 메소드)는 최종 QObject에 대한 참조를 보유하므로 대상 QObject는 수동으로 가비지 수집되지 않습니다 연결을 끊거나 소스 QObject를 제거하십시오.,

from PyQt5.QtWidgets import QApplication, QMainWindow 

app = QApplication([]) 

def create_win(): 
    win = QMainWindow() 
    win.show() 

    # case 1 
    # app.aboutToQuit.connect(win.repaint) # this is a qt slot, so win can be deleted 

    # case 2 
    # app.aboutToQuit.connect(win.size) # this is not a qt slot, so win can't be deleted 

    # win should get garbage-collected here 

create_win() 

app.exec_() 
+0

슬롯으로 꾸며지지 않은 호출 대상에 연결해서는 안된다는 것을 진지하게 제안하고 있습니까? 그것은 임의적이고 완전히 불필요한 제한으로 보인다. 자신의 예제에서'win.size'와 같이 우리가 제어 할 수없는 callables는 어떻습니까? pyqt 프로그램에서 가비지 콜렉션에 대해 걱정할 필요가있는 유일한 시간은 실제로 측정 가능한 문제를 일으키는시기입니다. 귀하의 본보기는 그것을 보여주지 못하기 때문에 여기서 어떤 점을 보이는지 보지 못합니다. 메인 윈도우는 어쨌든 응용 프로그램의 수명 동안 살아 있어야하므로, 그것을 명백하게 삭제하는 것은 거의 의미가 없습니다. – ekhumoro

+0

@ekhumoro 나는 결코 "결코"말하고 있지 않다. 나는 가능한 한 피한다. OP의 경우에는 사소하다. 필자의 예는 너무 길다. 예, 내가 말한 것을 보여주는 최소한의 테스트 케이스 일 뿐이다. 더 복잡한 시나리오에서 미묘하게 발생하기 때문에 문제의 현실적인 사례가 아닙니다. 여기에 하나가 있습니다 : 예를 들어 정상적인 영구 QMainWindow로 바꾸고 결함이있는 객체는 환경 설정 QDialog입니다. 환경 설정 대화 상자가 닫히면 참조가 해당 메소드 중 하나에 보관되므로 삭제되지 않습니다. 그리고 나서, QDialog는 신호 방출을 계속받을 것입니다 ... –

+0

@ekhumoro 좀 더 현실적인 예제를 만들려고 노력했고, 부분적으로 잘못되었음을 발견했습니다 : 연결되지 않은 방법, 파이썬 메소드에 대해서는 객체에 대한 참조를 보유하지 않지만 C++ 메소드는 다음을 수행합니다 : http://pastebin.com/XS4q2aHu 레이블을 닫으면'size'와 같은 C++ 메소드가 사용될 때 인쇄가 계속되지만 파이썬 메소드 (예 :'faultySlot '). –