PyQt : Linking buttons to functions in my program - python

So lets say i have this ui that has 2 empty text spots to fill and a 'Run' button.
I want to make it that the 2 empty text spots go to some values in the program and the run button will basically run the python 'Main' program ...
how can i do that ?

In PyQt5 the QWidgets module provides a set of UI elements to create classic desktop-style user interfaces. Widgets can display data and status information, receive user input, and provide a container for other widgets that should be grouped together. A widget that is not embedded in a parent widget is called a window.A parent widget containing various child widgets.So first you start to write a code for your window as
window=QtWidgets.QWidget()
(The QWidget class is the base class of all user interface objects).Once your window is created you need to set a layout for your UI window. There are many classes for layouts in Qt but most common are QVBoxLayout(to line up widgets vertically.) and QHBoxLayout(to line up widgets horizontally.) and many a times they both are used to make a custom layout. Now create your QVBoxLayout as
vbox=QWidgets.QVBoxLayout()
(note here that vbox is just a variable name).The next thing is to place widgets inside the window which can be done as
text_1=QtWidgets.QLineEdit()
text_2=QtWidgets.QLineEdit()
run_btn=QtWidgets.QPushButton("run")
text_3=QtWidgets.QLineEdit()
Note that in QPushButton we can give the name of the button as its argument(ex-run in this case). Now is the time for events and signals.
To connect the PushButton to a function , we write btn.clicked.connect(function_name) here btn is our PushButton.Note here that the function_name is without parenthesis which means that we have not called the function , just connected the button to the function (when the user will click the button the function gets executed).Foramlly this can be written as
run_btn=QtWidgets.QPushButton("run")
def main():
data_1=text_1.text()
data_2=text_2.text()
text_3.setText(str(int(data_1)+int(data_2)))
Now in our main function we first collected the data from text_1 and text_2 (there is a text() method for QLineEdit to get the data from QLineEdit as a str).So our main function takes the values of both text_1 and text_2 and adds them (it will raise an error if the values entered cannot be converted into integers) and sets that value to the text_3 by setText() method.
Now you have to pack the widgets in our vbox which we created earlier as
vbox.addWidget(text_1)
vbox.addWidget(text_2)
vbox.addWidget(run_btn)
vbox.addWidget(text_3)
And now set the layout of our window as
window.setLayout(vbox)
And to show the window as
window.show()
By now one thing is missing and that's the line
app=QtWidgets.QApplication(sys.argv)
This line is necessary as every PyQt5 application must create an application object. The sys.argv parameter is a list of arguments from a command line.
Now we have to create the mainloop of the application. The event handling starts from this point. The app.exec_() method runs our application and then provide a clean exit.
Now putting all together :
import sys
from PyQt5 import QtWidgets
app=QtWidgets.QApplication(sys.argv)
window=QtWidgets.QWidget()
vbox=QtWidgets.QVBoxLayout()
text_1=QtWidgets.QLineEdit()
text_2=QtWidgets.QLineEdit()
run_btn=QtWidgets.QPushButton("run")
text_3=QtWidgets.QLineEdit()
def main():
data_1=text_1.text()
data_2=text_2.text()
text_3.setText(str(int(data_1)+int(data_2)))
run_btn.clicked.connect(main)
vbox.addWidget(text_1)
vbox.addWidget(text_2)
vbox.addWidget(run_btn)
vbox.addWidget(text_3)
window.setLayout(vbox)
window.show()
sys.exit(app.exec_())
This will make a UI window like this :
Hope it helps.
Please do comment in case of some problem .
Happy coding!

Related

Multiple QRadioButton error

I'm using PyQt5 to create a program. I created 3 Radio Buttons, but when I check the first button and check the second button after that. The program will run both of the functions which are connected to these buttons. How I can make it only run the function which is connected to that button. Thanks.
def __init__(self):
super(Program, self).__init__()
self.ui = Ui_APIManager()
self.ui.setupUi(self)
self.show()
self.ui.add_btn.toggled.connect(self.start)
self.ui.check_btn.toggled.connect(self.start)
self.ui.delete_btn.toggled.connect(self.start)
def start(self):
if self.ui.add_btn.isChecked():
self.ui.third_lbl.setEnabled(True)
self.ui.first_lbl.setText('Tool name')
self.ui.second_lbl.setText('ID')
self.ui.third_lbl.setText('Username')
self.ui.action_btn.clicked.connect(self.add_user)
elif self.ui.check_btn.isChecked():
self.ui.first_lbl.setText('Type of search')
self.ui.second_lbl.setText('Keyword')
self.ui.third_lbl.setEnabled(False)
self.ui.action_btn.clicked.connect(self.check_user)
elif self.ui.delete_btn.isChecked():
self.ui.first_lbl.setText('Type of search')
self.ui.second_lbl.setText('Keyword')
self.ui.third_lbl.setEnabled(False)
self.ui.action_btn.clicked.connect(self.delete_user)
Qt signals can have multiple slots attached to them. Every time you click a button the start function is adding another connection to the action_button.clicked signal.
You will need to disconnect any existing slots from the signal first to achieve the desired behaviour. You can disconnect everything from self.ui.action_btn all at once by calling its disconnect() function.
Rather than trying to reassign the roles of the GUI elements you have created, you would be better off creating separate widgets containing the elements for each checkbox state and switching between them. You might find QStackedWidget useful.

Adding QFileDialog as a widget inside another QDialog

I'm attempting to create a dialog which contains two child widgets: on the left side a QFileDialog instance so users can select files, and on the right side a separate widget which will be used to show a preview of the selected file if it is of a certain type.
The problem is that the dialog opens up and I can see the "preview" widget just fine, but the QFileDialog is not showing up at all.
This short example demonstrates my problem:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
app = QApplication([])
main_dialog = QDialog()
main_dialog.setWindowTitle('My Dialog')
layout = QHBoxLayout(main_dialog)
file_dialog = QFileDialog(main_dialog, Qt.Widget)
file_dialog.setOption(QFileDialog.DontUseNativeDialog)
layout.addWidget(file_dialog)
preview = QLabel('Preview', main_dialog)
layout.addWidget(preview)
main_dialog.show()
app.exec_()
Some things that I've tried:
Add file_dialog.show() before/after main_dialog.show(): this shows up the QFileDialog, but in a different window; I want the file dialog to appear inside main_dialog, not as a separate window;
Do not pass Qt.Widget to the QFileDialog constructor, to no effect;
Do not pass main_dialog as parent to QFileDialog, again no effect;
Change main_dialog to a QWidget just to see if it changed anything, it did not;
I've searched the docs but did not find a suitable solution.
Any hints? Also, suggestions on how to accomplish the task of allowing the user to select a file and display a preview of the file in the same window are welcome.
Context: this is a port of an old application written for Qt3. Qt3's QFileSystem dialog had this "preview" functionality built-in; I'm trying to reproduce the same functionality in Qt5.
Versions
Python 2.7
PyQt 5.5.1
I've also tried with Python 3.6 (from conda-forge) but obtained the same behavior.
You need to turn off the Qt.Dialog flag in the file dialog's windowFlags...
file_dialog.setWindowFlags(file_dialog.windowFlags() & ~Qt.Dialog)
Otherwise the QFileDialog will always be created as a top level window. Works for me anyway.

pyqt. how to add and delete widgets?

i use python 2.7 + qt4.8
how to dynamically change the number of widgets in the window? I need to remove all the widgets and create new ones in the right quantity. testarovaniya made for a simple script:
import sys
from PyQt4 import QtCore, QtGui, uic
class MainForm(QtGui.QDialog):
def __init__(self):
super(MainForm, self).__init__()
uic.loadUi("testQTwindow.ui", self)
self.connect(self.addBtn, QtCore.SIGNAL("clicked()"), self.addBtnClick)
self.connect(self.delBtn, QtCore.SIGNAL("clicked()"), self.delBtnClick)
def addBtnClick(self):
self.tempBtn = QtGui.QPushButton('button')
self.gridLayout_2.addWidget(self.tempBtn)
def delBtnClick(self):
while True:
item = self.gridLayout_2.takeAt(0)
if not item:
break
self.gridLayout_2.removeWidget(item.widget())
app = QtGui.QApplication(sys.argv)
form = MainForm()
form.show()
sys.exit(app.exec_())
and load this UI: https://yadi.sk/d/jBOmSubYhqbjm
I have two buttons. One for adding buttons to QScrollArea with gridLayout. And the second to remove all the widgets in the QScrollArea. Adding works. I can see how there are new buttons. But when you press the cleaning button does not disappear, and new ones continue to appear over the old ones. The old button can also be pressed, which suggests that they work, and not just the ghosts that are cleaned redrawing window.
I try repaint() and update() functions - but it has no effect...
This is a simple example, but even he is not working. And I do not need to add a button in the future, and whole blocks with a bunch of elements.
How to add and remove widgets dynamically?
This part of the loop should be enough:
while True:
item = self.gridLayout_2.takeAt(0)
I suspect you are attempting to delete widgets you already removed, and so prematurely ending your loop. There may have been an error message written somewhere.

PySide: Removing a widget from a layout

I'm trying to remove a Qt widget from a layout in a PySide application.
Here is a minimal example. It is a widget with 5 buttons in it, and the middle one is supposed to remove itself when clicked:
import sys
from PySide import QtGui
app = QtGui.QApplication(sys.argv)
widget = QtGui.QWidget()
layout = QtGui.QVBoxLayout()
buttons = [QtGui.QPushButton(str(x)) for x in xrange(5)]
def deleteButton():
b = layout.takeAt(2)
buttons.pop(2)
del b
buttons[2].clicked.connect(deleteButton)
map(layout.addWidget, buttons)
widget.setLayout(layout)
widget.show()
app.exec_()
What actually happens is this:
The button is unclickable and clearly isn't taken into consideration for the layout computations, but its image stays in place.
According to the Qt documentation, the correct way of deleting all objects from a layout is:
while ((child = layout->takeAt(0)) != 0) {
delete child;
}
Here I just want to delete the third button, so I just call takeAt(2), and then del b to call the destructor on that item. The button object is also .pop'd from the buttons list to make sure there is no leftover reference to the object. How does my code differ from the one in the Qt docs that would cause such a behavior?
Super simple fix:
def deleteButton():
b = layout.takeAt(2)
buttons.pop(2)
b.widget().deleteLater()
You first have to make sure you are addressing the actual button and not the QWidgetItem that is returned from the layout, and then call deleteLater() which will tell Qt to destroy the widget after this slot ends and control returns to the event loop.
Another example illustrates why the problem is occurring. Even though you take the layout item, the underlying widget is still parented to the original layouts widget.
def deleteButton():
b = layout.takeAt(2)
buttons.pop(2)
w = b.widget()
w.setParent(None)
This is not the preferred way, as it still leaves the cleanup of the object ambiguous. But it shows that clearing the parent allows it to leave the visual display. Use deleteLater() though. It properly cleans everything up.
The answer that 'jdi' provided is valid, although If anyone is interested, I tried implementing what is suggested in the Qt Documentation with the loop of every child Widget, and I got the following code working in Python PySide6:
def delete():
while ((child := layout.takeAt(0)) != None):
child.widget().deleteLater()

PyQT QPushButton.setMenu? How to make it work?

im just a beginner in PyQT.
and im not sure if my thread title is the correct thing to put for my problem.
im having a problem creating a popmenu on a Qpushbutton.
based on the doc of QT docs
i need to make a QPushButton.setMenu (self, QMenu menu)
but i really dont know where to start.. i cant find a sample on how to use this.
please help me making one.
The basic idea is that you first have to create a QMenu, then use the setMenu method to attach it to your push button. If you look at the QMenu documentation, you'll see that there is a method called addAction that will add menu items to your newly created QMenu. addAction is overloaded, so there are a lot of different ways to call it. You can use icons in your menu, specify keyboard shortcuts and other things. To keep things simple though, let's just add a menu item and give it a method to call if that item is selected.
from PyQt4 import QtGui, QtCore
import sys
class Main(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
pushbutton = QtGui.QPushButton('Popup Button')
menu = QtGui.QMenu()
menu.addAction('This is Action 1', self.Action1)
menu.addAction('This is Action 2', self.Action2)
pushbutton.setMenu(menu)
self.setCentralWidget(pushbutton)
def Action1(self):
print 'You selected Action 1'
def Action2(self):
print 'You selected Action 2'
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
main = Main()
main.show()
app.exec_()
Here we've created a push button (creatively named pushbutton). We then create a menu (again creatively named menu) using QtGui.QMenu(). The actions are created by calling addAction and giving it a string that will be used as the menu item text and a method (self.Action1 or self.Action2) that will be called if that menu item is selected. Then we call the setMenu method of pushbutton to assign our menu to it. When you run it and select an item, you should see text printed corresponding to the selected item.
That's the basic idea. You can look through the QMenu docs to get a better idea of the functionality of QMenu.

Categories

Resources