Closing a QWidget opened from a QMainWindow - python

I need to show a QWidget, which code is written in another module, when a certain button is pressed. To accomplish this, I wrote this code:
class Window(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
#A lot of stuff in here
#The button is connected to the method called Serial_connection
self.connect(self.btn_selection_tool3, SIGNAL("clicked()"), self.Serial_connection)
def Serial_connection(self):
LiveData.LiveData(self).show()
Doing this, I open a QWidget and it works fine. But, when I want to close this QWidget, I can not do it. This is the code of the QWidget:
class LiveData(QWidget):
def __init__(self,parent = None):
super(QWidget, self).__init__(parent)
#Another stuff in here
#I create a "close" button connected to another method
self.connect(self.closeBtn, QtCore.SIGNAL("clicked()"), self.StopAndClose)
def StopAndClose(self):
print "Closing window"
self.close() #HERE IS WHERE I HAVE THE PROBLEM
I´ve tried several options like: self.close(), self.accept() or even sys.exit(1). The problem with the latter sys.exit(1) is that it closes the QWidget and the QMainWindow. So, how can I close this QWidget only? Hope you can help me.

You probably want your QWidget to be a QDialog. If it's a temporary modal widget, you should be calling the dialog like this
dialog = LiveData.LiveData(self)
dialog.exec_()
If you just want to show the dialog at the same time as your main window, and users are meant to interact with both (though from a design perspective, this doesn't sound like a great idea), you can continue to use .show()
Also, you should use the new-style signal/slot syntax. The old syntax hasn't been used for many years.
self.closeButton.clicked.connect(self.StopAndClose)
Though, for a QDialog you can just do
self.closeButton.clicked.connect(self.accept)

Related

QPushButton shortcut does not work properly

In this simple pyqt5 app, I have a QPushButton and I define a shortcut for it. I want to change its text every time it is triggered. Problem is that the shortcut works only for the first time. How can I fix it?
from PyQt5.QtWidgets import QPushButton, QMainWindow, QApplication
import sys
class window(QMainWindow):
def __init__(self):
super(window, self).__init__()
self.btn = QPushButton('&Connect', self)
self.btn.setShortcut('Ctrl+C')
self.btn.pressed.connect(self.btn_func)
def btn_func(self):
if self.btn.text() == '&Connect':
self.btn.setText('Dis&connect')
else:
self.btn.setText('&Connect')
def main():
app = QApplication(sys.argv)
win = window()
win.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
As explained in the text property documentation [emphasis mine]:
If the text contains an ampersand character ('&'), a shortcut is automatically created for it. [...] Any previous shortcut will be overwritten or cleared if no shortcut is defined by the text
I know that the above might seem confusing, as it seems that the shortcut is overwritten or cleared only if no shortcut is defined by the text, consider it like this:
Any previous shortcut will be overwritten, or it is cleared if no shortcut is defined by the text
The solution is to always reset the shortcut after setting the new text:
def btn_func(self):
if self.btn.text() == '&Connect':
self.btn.setText('Dis&connect')
else:
self.btn.setText('&Connect')
self.btn.setShortcut('Ctrl+C')
Note that using the button's text for comparison is considered bad practice, for three reasons:
the text of a button could (should) be localized;
you could easily forget to correctly update all the & texts, making the function behave in the wrong way;
some QStyles override existing mnemonics and change them by themselves, which also causes the text to change without any warning;
The most preferred way to achieve what you want would be to use an internal flag for the current state, and also a QAction with its own shortcut.
class Window(QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.btn = QPushButton('&Connect', self)
self.btn.clicked.connect(self.btn_func)
self.connectAction = QAction('Toggle connection', self)
self.connectAction.setShortcut('Ctrl+c')
self.connectAction.triggered.connect(self.btn.animateClick)
self.addAction(self.connectAction)
self.connected = False
def btn_func(self):
self.connected = not self.connected
if self.connected:
self.btn.setText('Dis&connect')
else:
self.btn.setText('&Connect')
Also note that:
you should not use the pressed() signal, as it's standard convention to consider a button clicked when the user presses and releases the mouse button while inside the button area (so that the pressed action could be "undone" by moving the mouse away if the mouse button was pressed by mistake on the button); use the clicked() signal instead;
I changed the class name using a capitalized Window, as classes should always use capitalized names and lower cased names should only be used for functions and variables;
I used the animateClick slot to show that the button was clicked (as a visual feedback is always preferable), but you can directly connect to the function: self.connectAction.triggered.connect(self.btn_func);

How to resize QWidget without intermediate paint

During the study, Qt encountered such a problem. Suppose I have a QWidget on the QMainWindow. How can I make sure that when I resize QMainWindow, QWidget on this QMainWindow do not repaint content until the resizing does not stop.
Yeah, I saw this example How to disable multiple auto-redrawing at resizing widgets in PyQt?
But when I tried this method it's just locked widget content. I just wondered if it was possible to make sure that the contents of the QWidget did not change while we resizing MainWindow. Please tell me, is this possible?
Thanks a lot.
I'm still guessing slightly as to what you want exactly but it sounds as if you essentially want two modes for your paintEvent method -- the normal one that takes care of rendering the widget most of the time and a second, lightweight, mode that can be used whilst the widget is being resized.
If that's the case then you could try something like the following...
#!/usr/bin/python3
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class widget(QWidget):
def __init__(self):
super().__init__()
self.resize_timer = QTimer(self)
self.resize_timer.setSingleShot(True)
self.resize_timer.setInterval(100)
self.resize_timer.timeout.connect(self.delayed_update)
def delayed_update(self):
self.update()
def paintEvent(self, event):
if self.resize_timer.isActive():
print("painting deferred")
# Your `lightweight' rendering goes here and will be used
# while the widget is being resized.
else:
print("painting now")
# Full rendering code goes here.
def resizeEvent(self, event):
super(widget, self).resizeEvent(event)
self.resize_timer.start()
if __name__ == '__main__':
app = QApplication(sys.argv)
f = widget()
f.show()
sys.exit(app.exec_())
Note that it is essentially just a simple modification of the code in the answer you linked to.

PyQt5 QWidget code uses un-initialized variable

I am following a tutorial on zetcode.com and I seem to have run into trouble. This code is supposed to be very straight forward and so I pasted it below.
This is all a part of an instance of the QWidget class (the base class of all UI objects). I have realized that this is one of the fundamental classes I need to understand in order to write a GUI, and I am simply puzzled on what is going on in the program.
The program is simple enough: PyQt opens a window, you are then able to exit out of that window via the 'x' button. And upon clicking the 'x' a message inquiring "Are you sure to quit?" allows you to continue to exit or cancel.
import sys
from PyQt5.QtWidgets import QWidget, QMessageBox, QApplication
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Message box')
self.show()
def closeEvent(self, event):
reply = QMessageBox.question(self, 'Message',
"Are you sure to quit?", QMessageBox.Yes |
QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
So what doesn't make sense?
The closeEvent() method that QWidget calls. The method seemingly accepts a variable "event" that is never initialized but somehow passed into the function. The methods "event.accept()" and "event.ignore()" are then called on an object that previously was never initialized.
I am a noob in PyQt/Qt and maybe it's a misunderstanding of Python too. Here is documentation on the function http://doc.qt.io/qt-5/qwidget.html#closeEvent, that may clarify things.
The method seemingly accepts a variable "event" that is never
initialized but somehow passed into the function.
That is how a method works. Consider this simple function:
def print_a_word(word):
print(word)
It takes an argument word, that we did not initialized. When you call the function, then you need to define what word is:
word = "unicorn"
print_a_word(word)
If you look at the doc in more details, you'll see that event is a QCloseEvent, and it is "initialized" somewhere else in QWidget
The QCloseEvent class contains parameters that describe a close event.
Close events are sent to widgets that the user wants to close, usually
by choosing "Close" from the window menu, or by clicking the X title
bar button. They are also sent when you call QWidget::close() to close
a widget programmatically.

How to close a QDialog

I've been trying to close a QDialog window that is branching off of my main window. The following have not worked for me so far:
self.close()
QDialog.close()
I tried other commands such as exit and exec_() with no luck.
The most common error I get is
[className] object has no attribute 'close'
# Creating our window
class Ui_MainWindow(object):
# Sets up GUI
def setupUi(self, MainWindow):
[GUI CODE]
# Sets text for parts of GUI
def retranslateUi(self, MainWindow):
[MORE GUI CODE]
# Function handling screencap on click and metadata for filenames
def cap_on_Click(arg1,arg2):
popup = QDialog()
popup_ui = Ui_Dialog()
popup_ui.setupUi(popup)
popup.show()
sys.exit(popup.exec_())
The above is my main window
class Ui_Dialog(object):
def setupUi(self, Dialog):
[GUI CODE]
def retranslateUi(self, Dialog):
[MORE GUI CODE]
def button_click(self, arg1):
self.close()
The second block is the dialog window code. How do I close this dialog window?
First of all, sorry for the links related to C++, but Python has the same concept.
You can try using the reject or accept or done function to close the dialog box. By doing this, you're setting the return value appropriately (Rejected, Accepted or the one you specify as the argument).
All in all, you should try calling YourDialog.done(n) to close the dialog and return n and YourDialog.accept() or YourDialog.reject() when you want it accepted/rejected.
Since a QDialog is a QWidget, and a QWidget has the close() method, I don't understand how it can not work. You should never invoke popup.exec_() though, since it will happily require a lot of your code to be reentrant without you realizing it. It is unnecessary - you already have the application event loop running and on the call stack when cap_on_Click is executing.
After popup.show(), the dialog will be visible and usable until it gets accepted or rejected by the user. Hopefully your design for the dialog connects the button box's accepted() and rejected() signals to the dialog's accept() and reject() slots. That is the default behavior of a QDialog template provided with Qt Creator and perhaps Qt Designer as well, but you should check it by going into the signal/slot editor mode while viewing the Ui file.
I guess the problem is that Ui_Dialog does not inherit QDialog, so reject(), accept() and done() is not defined. I think
class Ui_Dialog(object):
should be changed to
class Ui_Dialog(QDialog):
But I can not test it because minimal working example is not provided.
I know it's over 5months but I choose to drop this comment here, it might be of help to others tomorrow.
To be able to close or cancel an opened dialog box, using only self.close would close the entire program.
use this example:
self.dlg = QDialog(self)
self.dlg.setWindowTitle("Admin")
self.dlg.setGeometry(100,100,300,200)
btnBox = QDialogButtonBox()
btnBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
btnBox.rejected.connect(self.close1)
def close1():
self.dlg.close()

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