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.
Related
I have a QlistWidget and I need to implement on this an Infinite Scroll, something like this HTML example:
https://scrollmagic.io/examples/advanced/infinite_scrolling.html
Basically, when the user scrolls to the last item of the list, I need to load more items and dynamically append it in the QlistWidget.
Is it possible? I didn't find any example yet.
There are likely many ways to achieve this task, but the easiest I found is to watch for changes in the scroll bar, and detect if we're at the bottom before adding more items to the list widget.
import sys, random
from PyQt5.QtWidgets import QApplication, QListWidget
class infinite_scroll_area(QListWidget): #https://doc.qt.io/qt-5/qlistwidget.html
def __init__(self):
super().__init__() #call the parent constructor if you're overriding it.
#connect our own function the valueChanged event
self.verticalScrollBar().valueChanged.connect(self.valueChanged)
self.add_lines(15)
self.show()
def valueChanged(self, value): #https://doc.qt.io/qt-5/qabstractslider.html#valueChanged
if value == self.verticalScrollBar().maximum(): #if we're at the end
self.add_lines(5)
def add_lines(self, n):
for _ in range(n): #add random lines
line_text = str(random.randint(0,100)) + ' some data'
self.addItem(line_text)
if __name__ == "__main__":
app = QApplication(sys.argv)
widget = infinite_scroll_area()
sys.exit(app.exec_())
You can directly grab scroll wheel events by overriding the wheelEvent method of QListWidget, then do the logic there which solves the potential problem of not starting out with enough list items for the scrollbar to appear. If it's not there, it can't change value, and the event can't fire. It introduces a new problem however as scrolling with the mouse wheel is not the only way to scroll the view (arrow keys, page up/down keys, etc). With the number of classes and subclasses in any gui library, it becomes imperative to get really familiar with the documentation. It's a little inconvenient that it isn't as comprehensive for python specifically, but I think the c++ docs are second to none as far as gui library documentation goes.
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!
I'm trying to modify a program written using pyQt (specifically, Anki). I want the program to briefly flash a picture (stored as a file on my hard drive) and then continue running normally.
This code will be inserted at some arbitrary point in the program. This is an ad-hoc single-user patch to an existing program - it does not need to be fast or elegant or easily-maintained.
My problem is that I know very little about pyQt. Do I need to define an entire new "window", or can I just run some sort of "notification" function with an image inside it?
QSplashScreen will be useful for this. It is mainly used for displaying certain image/text while a program loads, but your case also looks ideal for this. You can close it with clicking on it, or additionally you can set a timer to auto-close it after some time.
Here is a simple example with a dialog that has one button. When pressed it'll show the image and close after 2 seconds:
import sys
from PyQt4 import QtGui, QtCore
class Dialog(QtGui.QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
layout = QtGui.QVBoxLayout()
self.setLayout(layout)
self.b1 = QtGui.QPushButton('flash splash')
self.b1.clicked.connect(self.flashSplash)
layout.addWidget(self.b1)
def flashSplash(self):
# Be sure to keep a reference to the SplashScreen
# otherwise it'll be garbage collected
# That's why there is 'self.' in front of the name
self.splash = QtGui.QSplashScreen(QtGui.QPixmap('/path/to/image.jpg'))
# SplashScreen will be in the center of the screen by default.
# You can move it to a certain place if you want.
# self.splash.move(10,10)
self.splash.show()
# Close the SplashScreen after 2 secs (2000 ms)
QtCore.QTimer.singleShot(2000, self.splash.close)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
main = Dialog()
main.show()
sys.exit(app.exec_())
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()
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.