简体   繁体   中英

Initiating a custom QWidget within another QWidget class' function

I'm new to python and pyqt. I am am trying to create a matrix of QToolButtons where upon pressing a button, a QDialog pops up for user input (more than one field).

I have a class for a button matrix object and a class for a dialog but can't seem to get a function within the button matrix class initiate an instance of the dialog class / widget.

Can anyone please advise me on what I'm doing wrong?

I have provided the code below:

from PyQt4 import QtGui
from PyQt4.QtGui import QApplication, QWidget, QFormLayout, QInputDialog, QPushButton, QToolButton, QLabel, QVBoxLayout, QHBoxLayout, QLineEdit

class Pixel(object):
    def __init__(self, pixel_number, r_value, g_value, b_value):
        self.pixel = pixel_number
        self.red_value = r_value
        self.green_value = g_value
        self.blue_value = b_value
        
class inputdialogdemo(QWidget):
    
    def __init__(self, parent = None):
        QWidget.__init__(self, parent)
        #super(inputdialogdemo, self).__init__(parent)
        
        layout = QFormLayout()
        self.btn1 = QPushButton("Enter red value")
        self.le1 = QLineEdit()
        self.btn1.clicked.connect(self.getRed)
        layout.addRow(self.btn1,self.le1)
    
        self.btn2= QPushButton("Enter green value")
        self.le2 = QLineEdit()
        self.btn2.clicked.connect(self.getGreen)
        layout.addRow(self.btn1,self.le2)
      
        self.btn3 = QPushButton("Enter blue value")
        self.le3 = QLineEdit()
        self.btn3.clicked.connect(self.getBlue)
        layout.addRow(self.btn3,self.le3)
      
        self.setLayout(layout)
        self.setWindowTitle("RGB input dialog ")
        
    def getRed(self):
        num, ok = QInputDialog.getText(self, 'Red Input Dialog', 'Enter your name:')
        
        if ok:
            self.le1.setText(str(num))
            
    def getGreen(self):
        num,ok = QInputDialog.getInt(self,"Green input dualog","enter a number")
        
        if ok:
            self.le2.setText(str(num))  
    
    def getBlue(self):
        num,ok = QInputDialog.getInt(self,"Blue input dualog","enter a number")
        
        if ok:
            self.le3.setText(str(num))    


class ClusterArray(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        #self.button_layout = QHBoxLayout()
        self.button_layout = QtGui.QGridLayout()
        self.widget_layout = QtGui.QGridLayout()
        for cluster_number in range(1, 15):
            for pixel_number in range(1, 5):
                    button = QToolButton()
                    button.setText(str(cluster_number) + str(pixel_number))
                    button.setObjectName(f"Cluster{cluster_number},Pixel{pixel_number}")
                    button.released.connect(self.button_released)
                    self.button_layout.addWidget(button, cluster_number, pixel_number)

        self.status_label = QLabel('No button clicked')

        self.widget_layout.addItem(self.button_layout)
        self.widget_layout.addWidget(self.status_label)
        self.setLayout(self.widget_layout)
        ex = inputdialogdemo()
        
    def button_released(self):
        sending_button = self.sender()
        self.status_label.setText('%s Clicked!' % str(sending_button.objectName()))
        ex = inputdialogdemo()
        ex.show()
        #i, okPressed = QInputDialog.getInt(self, "Get integer","Percentage:", 28, 0, 100, 1)
        
if __name__ == '__main__':
    app = QApplication(sys.argv)
    widget = ClusterArray() 
    widget.show()
#   ex = inputdialogdemo()
#   ex.show()
    sys.exit(app.exec_()

At the moment I've just tried to get my class' function to create an object from some demo code in a class called 'inputdialogdemo'

Also, I would like to keep the inputted values associated with the corresponding button on the matrix somehow. I'm thinking the values should be stored in another object that each button represents. My object would be 'Pixel' that holds red, green and blue values. I have yet to code this functionality. Does this method sound feasible?

The inputdialogdemo instance is correctly created both in the __init__ and in button_released , the problem is that as soon as those function return, the ex instance gets garbage collected : since there is no persistent reference ( ex is just a local variable), python automatically deletes it to avoid unnecessary memory consumption.

Since you're needing a dialog , the best solution is to inherit from QDialog instead of QWidget ; this has two important benefits: it keeps the dialog modal (it stays on top of other windows and avoid interaction with them) and provides the exec_() method, which does not return until the dialog is closed; then you can add a QDialogButtonBox for standard Ok/Cancel buttons, and connect its accepted and rejected to the accept() and reject() slots of the dialog.

from PyQt4.QtGui import (QApplication, QWidget, QFormLayout, QInputDialog, QPushButton, QToolButton, 
    QLabel, QVBoxLayout, QHBoxLayout, QLineEdit, )

class inputdialogdemo(QDialog):
    def __init__(self, parent = None):
        # ...
        buttonBox = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel)
        layout.addRow(buttonBox)
        buttonBox.accepted.connect(self.accept)
        buttonBox.rejected.connect(self.reject)

class ClusterArray(QWidget):
    # ...
    def button_released(self):
        sending_button = self.sender()
        self.status_label.setText('%s Clicked!' % str(sending_button.objectName()))
        ex = inputdialogdemo()
        

Some suggestions:

  • if you need a numerical value, don't use QLineEdit, but QSpinBox;
  • to add a layout to another, use setLayout() , not addItem() ;
  • to connect to a button click, use the clicked signal, not released ;
  • while special characters are not strictly forbidden for object names, it's usually better to avoid them; also, use the object names for actual object names, not for keeping track of some properties
  • you can keep track of custom properties of any QObject using dynamic properties :
    button.setProperty('cluster', cluster_number)
    button.setProperty('pixel', pixel_number)
  • unless you have mandatory system requirements, you should really consider to switch to PyQt5, as PyQt4 is considered obsolete and deprecated/unsupported since 2015;
  • always prefer capitalized names for classes, as lower case names are normally used for variables and attributes only; read more on the Style Guide for Python Code ;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM