cornerWidget disappears when there isn't any tab - python

I'm working on a window which has an empty QTabWidget when created. The user can add some tabs with a QPushButton set as cornerWidget.
My problem is that the cornerWidget works fine when there are tabs, but disappears when there isn't any tab. See code below:
class myWindow (QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
tabW = QtGui.QTabWidget()
self.layout().addWidget(tabW)
#tabW.addTab(QtGui.QWidget(), 'tab1')
tabW.setCornerWidget(QtGui.QPushButton())
self.show()
myWIndow01 = myWindow()

It's the correct behaviour of QTabWidget: when it's empty, it displays nothing.
A workaround is to set the minimum size of the button, like this:
self.button=QtGui.QPushButton("my button")
tabWidget.setCornerWidget(self.button)
tabWidget.cornerWidget().setMinimumSize(self.button.sizeHint())

Related

PyQt5 - How to dynamically add widgets to window without layout

I've been trying to figure this one out, the reason I don't want to use a layout is because the widgets scale with the window when resizing and I want them to stay put, I have made it where I can drag and drop the widgets but with them being in a layout it messes it up, please can someone help me figure this out.
I Want to be able to add lets say a label widget, I want to have it where I can press a button and it will create a new label widget in my window, I have done this part already but I want to be able to add widgets without the layout.
You just have to set another widget that is part of the window (or the window itself) as parent and make it visible with the show method:
import random
import sys
from PyQt5 import QtCore, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
button = QtWidgets.QPushButton("Add", self)
button.clicked.connect(self.handle_clicked)
self.resize(640, 480)
def handle_clicked(self):
pos = QtCore.QPoint(*random.sample(range(400), 2))
label = QtWidgets.QLabel(self)
label.move(pos)
label.setText("{}-{}".format(pos.x(), pos.y()))
label.show()
def main():
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec())
if __name__ == "__main__":
main()

How to transfer date selection from calendar widget to QLineEdit

I'm playing around with PyQt5 (which I just started learning yesterday).
I'm trying to create a window/layout, with two entry boxes (to enter 'start' and 'end' dates), so that when each one is clicked, the QCalendarWidget is triggered to popup, and when the user selects the date, the date is entered into the QLineEdit field.
So far, it simply shows a blank window, but I'm not sure what I'm doing wrong.
class selectedDate(QWidget):
def __init__(self):
super(selectedDate, self).__init__()
self.layout = QVBoxLayout(self)
self.selection = QLineEdit("Click to Enter Date", self)
self.layout.addWidget(self.selection)
self.layout.addWidget(self.selection)
self.selection.installEventFilter(self)
def mousePressEvent(self, e):
self.myCal()
super(selectedDate, self).mousePressEvent(e)
def eventFilter(self, object, e):
if self.layout.indexOf(object) != -1:
if e.type() == e.MouseButtonPress:
pass
return super(selectedDate, self).eventFilter(object, e)
def myCal(self):
self.cal = QCalendarWidget(self)
self.cal.setGridVisible(True)
self.cal.move(10, 20)
self.cal.clicked[QDate].connect(self.showDate)
self.date = self.cal.selectedDate()
self.selection.setText(self.date.toString())
self.setGeometry(300, 300, 415, 350)
self.setWindowTitle('Calendar')
self.show()
def showDate(self, date):
self.selection.setText(date.toString())
app = QApplication(sys.argv)
top = selectedDate()
app.exec_()
There's quite a lot of issues, let's work through some.
To see a window, you need to call QWidget.show(). Here you only call self.show() in myCal method. But myCal is only called with a mouse click. Surely you want to display the window right after starting the application. To do that you can simply put self.show() at the end of the __init__ method.
class SelectedDate(QWidget):
def __init__(self):
# layout stuff, QLineEdit, etc
self.show() # show your first window with the QLineEdit
Next, the mouse press event. The method mousePressEvent is actually never called! You can check that by adding a print statement in it.
It should be called when a MouseButtonPress is detected (in eventFilter)
Finally the calendar widget. We want to open it in a new window (QCalendarWidget doesn't open as a pop up by default, you need to do it yourself).
def myCal(self):
self.cal = QCalendarWidget(self)
self.cal.setGridVisible(True)
self.cal.clicked[QDate].connect(self.showDate)
# create a new window that contains the calendar
self.calendarWindow = QWidget()
hbox = QHBoxLayout()
hbox.addWidget(self.cal)
self.calendarWindow.setLayout(hbox)
self.calendarWindow.setGeometry(300, 300, 415, 350)
self.calendarWindow.setWindowTitle('Calendar')
# open this new window
self.calendarWindow.show()
Now some more advice. You should start by a simple app and build more functionality when it works. Writing a lot of code for only a blank window it not a good idea! So if you where to do this again, work by steps:
Show a window with a QLineEdit (write code, test that it works)
Implement the event filter (use print statements to see if it works)
Implement opening a new blank window when clicking the QLineEdit
Fill that blank window with the calendar
Connect the calendar to the QLineEdit text (that code was good by the way)
Also, you can use better variable names, some suggestions:
selectedDate -> SelectDateWidget
selection -> date_selection
mousePressEvent -> on_date_selection_clicked
myCal -> open_calendar
cal -> calendar
showDate -> on_calendar_clicked or update_date_selection_text

Communication between mianwindow and dialog in python

Hello I am working on data archive program with python 2.7. I have one mainWindow and there is some elements (Buttons, text lines etc.) Clicking a button open a dialog form page. User select their answer on that dialog page. Dialog page has a button named 'save'. When clicking save button dialog class saving user's selections to database. I want to do, when user clicked to save button on dialog, It will enable some elements on the mainWindow which is not enabled. I am doing this with these codes entering to dialog class and save button function:
self.ui.onceBut.setEnabled(True) etc.
But I am taking an error:
AttributeError: 'onceDlg' object has no attribute 'onceBut'
onceDlg is dialog pages class name.
How can I solve this and I can do what I want? Thanks in advance.
self in self.ui.onceBut.setEnabled(True) refers to dialog, so you get error because your onceBut is in your mainWindow not in onceDlg dialog.
Solution: as #Radio say - Communication between components in Qt are often done using signals and slots, but it's not the only way.
Easier way is to simply pass main window to dialog window, so you can manipulate with it's buttons, or whatever you want, inside dialog window. In next example I've done that in line dialog = Dialog(self), where self refers to MainWindow and it is used as mainWin inside Dialog. Run it, click on first button, dialog will show, click save button in dialog and second button in main will be changed and disabled.
I hope I've helped you.
import sys
from PyQt4 import QtCore, QtGui
class Dialog(QtGui.QDialog):
def __init__(self, mainWin):
QtGui.QDialog.__init__(self,mainWin)
self.setWindowTitle(self.tr("Dialog window"))
self.main = mainWin
button = QtGui.QPushButton()
button.setText( "Save (disable dummy button)" )
layout = QtGui.QVBoxLayout()
layout.addWidget(button)
self.setLayout(layout)
self.connect(button, QtCore.SIGNAL("clicked()"), self.save)
self.resize(200, 100)
def save(self):
self.main.button2.setEnabled(False)
self.main.button2.setText( "changed from dialog" )
class MainWindow(QtGui.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle(self.tr("Main window"))
self.button1 = QtGui.QPushButton()
self.button2 = QtGui.QPushButton()
self.button1.setText( "Open dialog" )
self.button2.setText( "Dummy" )
layout = QtGui.QVBoxLayout()
layout.addWidget(self.button1)
layout.addWidget(self.button2)
self.window = QtGui.QWidget()
self.window.setLayout(layout)
self.setCentralWidget(self.window);
self.connect(self.button1, QtCore.SIGNAL("clicked()"), self.showDialog)
self.resize(360, 145)
def showDialog(self):
dialog = Dialog(self)
dialog.show()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
main = MainWindow()
main.show();
sys.exit(app.exec_())

Displaying pop-up windows in Python (PyQt4)

I need to know how to be able to make a dialog pop-up when a user clicks a button.
I'm relatively new to both Python and PyQt/QtDesigner. I've only been using in them for about a month, but I think I have a good grasp.
Here's what I have: A main dialog (which is the main part of the application), which I designed in QtDesigner. I converted the .ui to .py using pyuic4easy.
Here's what I want to do: design a new dialog box in the QtDesigner and somehow make it pop up when a user clicks a button on the first (main) dialog.
Here's the code for my main dialog:
import sys
from PyQt4.QtCore import *
from loginScreen import *
class MyForm(QtGui.QDialog):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_Dialog()
self.ui.setupUi(self)
QtCore.QObject.connect(self.ui.pushButton, QtCore.SIGNAL('clicked()'), self.popup)
...
... Some functions ...
def popup(self):
#Pop-up the new dialog
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp= MyForm()
myapp.show()
sys.exit(app.exec_())
So as you can see, I've connected the first button to a method named 'popup', which needs to be filled in with code to make my second window pop up. How do I go about doing this? Remember that I already have designed my second dialog in QtDesigner, and I don't need to create a new one.
Thanks for all the help!
So as you can see, I've connected the first button to a method named
'popup', which needs to be filled in with code to make my second
window pop up. How do I go about doing this?
Pretty much the same way you do it for your main window (MyForm).
As usual, you write a wrapper class for your QtDesigner code for the second dialog (like you did with MyForm). Let's call it MyPopupDialog. Then in your popup method, you create an instance and then show your instance with either exec_() or show() depending whether you want a modal or modeless dialog. (If you are not familiar with Modal/Modeless concept, you might refer to the documentation.)
So the overall thing might look like this (with a couple of modifications):
# Necessary imports
class MyPopupDialog(QtGui.QDialog):
def __init__(self, parent=None):
# Regular init stuff...
# and other things you might want
class MyForm(QtGui.QDialog):
def __init__(self, parent=None):
# Here, you should call the inherited class' init, which is QDialog
QtGui.QDialog.__init__(self, parent)
# Usual setup stuff
self.ui = Ui_Dialog()
self.ui.setupUi(self)
# Use new style signal/slots
self.ui.pushButton.clicked.connect(self.popup)
# Other things...
def popup(self):
self.dialog = MyPopupDialog()
# For Modal dialogs
self.dialog.exec_()
# Or for modeless dialogs
# self.dialog.show()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp= MyForm()
myapp.show()
sys.exit(app.exec_())

uncheck radiobutton - PyQt4

In this sample of code:
from PyQt4.QtGui import QDialog, QPushButton, QRadioButton, QHBoxLayout, QApplication, QButtonGroup
import sys
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent=None)
button = QPushButton('Button')
self.radiobutton1 = QRadioButton('1')
self.radiobutton2 = QRadioButton('2')
#self.group = QButtonGroup()
#self.group.addButton(self.radiobutton1)
#self.group.addButton(self.radiobutton2)
#self.group.setExclusive(False)
layout = QHBoxLayout()
layout.addWidget(button)
layout.addWidget(self.radiobutton1)
layout.addWidget(self.radiobutton2)
self.setLayout(layout)
button.clicked.connect(self.my_method)
def my_method(self):
self.radiobutton1.setChecked(False)
self.radiobutton2.setChecked(False)
app = QApplication(sys.argv)
form = Form()
form.show()
app.exec_()
When the button clicked I expect the selected radioButton to be unchecked, but that never happens. If I uncomment the comment lines and run the code, then I can uncheck radioButtons. But another problem occurs. Because the group is not exclusive, I can set both radioButtons checked something that must not happens.
What should I do to be able to unckeck the buttons while only one button at a time can be selected?
This feels like cheating, but it works:
import sys
import PyQt4.QtGui as QtGui
class Form(QtGui.QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
button = QtGui.QPushButton('Button')
button.clicked.connect(self.my_method)
self.radiobutton1 = QtGui.QRadioButton('1')
self.radiobutton2 = QtGui.QRadioButton('2')
layout = QtGui.QHBoxLayout()
layout.addWidget(button)
layout.addWidget(self.radiobutton1)
layout.addWidget(self.radiobutton2)
self.setLayout(layout)
self.group = QtGui.QButtonGroup()
self.group.addButton(self.radiobutton1)
self.group.addButton(self.radiobutton2)
def my_method(self):
self.group.setExclusive(False)
self.radiobutton1.setChecked(False)
self.radiobutton2.setChecked(False)
self.group.setExclusive(True)
app = QtGui.QApplication(sys.argv)
form = Form()
form.show()
app.exec_()
As you've pointed out, when self.group.setExclusive(False) is set, you can untoggle both radio buttons.
And when self.group.setExclusive(True), only one radio button can be set.
So my_method simply calls self.group.setExclusive(False) so it can unset both radio buttons, then resets self.group.setExclusive(True).
PS. I think parent should not be set to None on this line:
super(Form, self).__init__(parent = None)
since if a non-trivial parent is sent to Form, you would probably want to pass that parent on to QDialog.__init__.
To anyone looking for a simple fix to this very annoying problem, connect each button to a slot that controls the CheckState of the other buttons.
Simply add the list of buttons you want to a QButtonGroup, get the list of buttons, check that the sender is not the same button, and uncheck others.
Assuming that you instantiate your buttons in a loop, you can easily implement this:
self.bg = QButtonGroup()
self.bg.setExclusive(False)
for button in list_of_buttons:
self.bg.addButton(button)
button.clicked.connect(self.uncheck_other_buttons)
def uncheck_other_btns(self):
for button in self.bg.buttons(): # returns the list of all added buttons
if self.sender() != button: # in PyQt5, button.objectName() fails if name isn't set,
# instead, simply check that the signal sender() object
# is not the same object as the clicked button
button.setChecked(False) # then set all other buttons to be unchecked

Categories