PyQt add widget to second window - python

I've got the following python code which opens a second window. I can't figure out how to add a label or pushbutton to this second window. I thought it would be easy but nothing I try seems to work. Thanks!
from PyQt4 import QtGui, QtCore
class Window(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
menu = self.menuBar().addMenu(self.tr('View'))
action = menu.addAction(self.tr('New Window'))
action.triggered.connect(self.handleNewWindow)
def handleNewWindow(self):
window = QtGui.QMainWindow(self)
window.setAttribute(QtCore.Qt.WA_DeleteOnClose)
window.setWindowTitle(self.tr('New Window'))
window.show()
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.resize(300, 300)
window.show()
sys.exit(app.exec_())

If the two windows are different, it makes more sense to create two class.
I guess the second one doesn't need to be a QMainWindow (= it doesn't need a menu and a toolbar and a status bar etc), so let's just make it a QWidget.
class SecondWindow(QtGui.QWidget):
def __init__(self,parent):
QtGui.QWidget.__init__(self,parent)
self.button=QtGui.QPushButton("my button !")
layout=QtGui.QHBoxLayout()
layout.addWidget(self.button)
self.setLayout(layout)
self.show()
In your main window, you cretae and instance of the class SecondWindow:
class FirstWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
...
self.show()
def handleNewWindow(self):
self.childWindow = SecondWindow(self)

If you just want a TopLevel window, using QtGui.QDialog seems to be more appropriate. To add button and label, you can do something like this:
def handleNewWindow(self):
window = QtGui.QMainWindow(self)
window.setAttribute(QtCore.Qt.WA_DeleteOnClose)
window.setWindowTitle(self.tr('New Window'))
button = QtGui.QPushButton("MY BUTTON!") #create button
label = QtGui.QLabel("MY LABEL!") # create label
CentralWidget = QtGui.QWidget() # create an empty widget
CentralWidgetLayout = QtGui.QHBoxLayout() # create a layout
CentralWidgetLayout.addWidget(label) # add your label to the layout
CentralWidgetLayout.addWidget(button) # add your button to the layout
CentralWidget.setLayout(CentralWidgetLayout) # assign your layout to the empty widget
window.setCentralWidget(CentralWidget) #make the assigned widget CentralWidget
window.show()

Related

How to remove a widget in PYQT6 after it was added using a CheckBox

I am developing a Python GUI using PYQT6. The code below is a reduced version of my code that illustrates my problem. When the GUI comes up first time, I want to show an unchecked CheckBox widget, and below it a DateEdit widget. In addition, when I check the CheckBox, a LineEdit widget is added to the left of the DateEdit widget. So far the software works fine. However, when I uncheck the CheckBox to remove the LineEdit widget from the layout, the LineEdit widget continues to show in the layout. Any help is appreciated.
import sys
from PyQt6.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QCheckBox,
QWidget, QHBoxLayout, QDateEdit, QLineEdit )
from PyQt6 import QtCore
from PyQt6.QtCore import QDate
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Example")
global layout3
layout1 = QHBoxLayout()
layout2 = QVBoxLayout()
layout3 = QHBoxLayout()
# Define the QCheckBox widget.
self.CheckBox = QCheckBox("Enable Sales", self)
self.CheckBox.toggled.connect(self.checkbox_toggled)
# Define the QLineEdit widget
self.item_entry = QLineEdit()
self.item_entry.setPlaceholderText("Enter item")
# Define the QDateEdit widget and set its date to the current date.
self.date_entry = QDateEdit()
self.date_entry.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.date_entry.setCalendarPopup(True)
self.date_entry.setEnabled(True)
current_dated = QDate.currentDate()
self.date_entry.setDate(current_dated)
# Outline the layouts and add to them the CheckBox and the DateEdit widgets.
# The QLineEdit widget will be added later dynamically.
layout1.addLayout(layout2)
layout2.addWidget(self.CheckBox, alignment=QtCore.Qt.AlignmentFlag.AlignCenter)
layout2.addLayout(layout3)
layout3.addWidget(self.date_entry)
widget = QWidget()
widget.setLayout(layout1)
self.setCentralWidget(widget)
def checkbox_toggled(self):
if self.CheckBox.isChecked() == True:
layout3.addWidget(self.item_entry)
layout3.addWidget(self.date_entry)
else:
layout3.removeWidget(self.item_entry)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
One solution to this problem would be to delete the widget each time the checkbox becomes unchecked, and recreate it when it becomes checked. THis will completely remove it and allow the DateEdit Widget to grow and be totally visible.
For example:
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Example")
layout1 = QHBoxLayout()
layout2 = QVBoxLayout()
self.layout3 = QHBoxLayout()
self.CheckBox = QCheckBox("Enable Sales", self)
self.CheckBox.toggled.connect(self.checkbox_toggled)
self.date_entry = QDateEdit()
self.date_entry.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.date_entry.setCalendarPopup(True)
self.date_entry.setEnabled(True)
current_dated = QDate.currentDate()
self.date_entry.setDate(current_dated)
layout1.addLayout(layout2)
layout2.addWidget(self.CheckBox, alignment=QtCore.Qt.AlignmentFlag.AlignCenter)
layout2.addLayout(self.layout3)
self.layout3.addWidget(self.date_entry)
widget = QWidget()
widget.setLayout(layout1)
self.setCentralWidget(widget)
def checkbox_toggled(self):
if self.CheckBox.isChecked() == True:
self.item_entry = QLineEdit()
self.item_entry.setPlaceholderText("Enter item")
self.layout3.addWidget(self.item_entry)
self.layout3.addWidget(self.date_entry)
else:
i = self.layout3.indexOf(self.item_entry)
self.layout3.takeAt(i)
self.item_entry.deleteLater()
P.S. I turned the layout3 into an instance attribute so that you could access it in the checkbutton slot method without needing to make it a global variable. Changing it was for my own preference and it is not necessary for the solution to work.

How can I get rid of the previous layout and set new Grid Layout in QMainWindow?

I am a newbie with PyQt. I am trying to organize my buttons on a grid layout, but I guess the window has a default layout already. How can I get rid of it and replace it with the new Grid Layout? I have contained the code block relevant with hashes ###, Here is my program:
import sys
from PyQt4 import QtCore, QtGui
from PyQt4.QtGui import QWidget
class MainWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QWidget.__init__(self)
self.setMinimumSize (800,600) # set minimum size for window
self.setWindowTitle("CoolPlay Kabul") # set window title
self.setWindowIcon(QtGui.QIcon("images/CoolPlay.png"))# set icon for Window
myMenu = self.menuBar()
File_Menu = myMenu.addMenu("&File")
Items_Menu = myMenu.addMenu("&Items")
Playlist_Menu = myMenu.addMenu("&Playlist")
Option_Menu = myMenu.addMenu("&Option")
Exit_Menu = myMenu.addMenu("&Exit")
File_Menu.addAction("New Time")
File_Menu.addAction("Delete Time")
File_Menu.addSeparator()
File_Menu.addAction("Exit")
Items_Menu.addAction("New Item")
Items_Menu.addAction("Delete Item")
Items_Menu.addSeparator()
Items_Menu.addAction("Toggle Segue")
Playlist_Menu.addAction("Clear Playlist")
Playlist_Menu.addAction("Save playlist")
Playlist_Menu.addAction("Load Playlist")
Playlist_Menu.addSeparator()
Playlist_Menu.addAction("Clear 'Played' Indication")
Option_Menu.addAction("Application Setup")
Exit_Menu.addAction("Help")
Exit_Menu.addAction("About")
######################################################
Overall_Layout = QtGui.QGridLayout(self)
self.setLayout(Overall_Layout)
Play_Button = QtGui.QPushButton(QtGui.QIcon("images/PLAY.bmp"), "PLAY",self)
Overall_Layout.addWidget(Play_Button,1,2)
Overall_Layout.addWidget(Play_Button,2,2)
########################################################
self.show()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
CoolPlay = MainWindow()
CoolPlay.show()
sys.exit(app.exec_())
QMainWindow is a special widget since it already has a preset layout as shown below:
So in this case you should not set a layout to the QMainWindow but to the central widget, but first establish a centralwidget, using the indicated thing we get the following:
######################################################
central_widget = QtGui.QWidget()
self.setCentralWidget(central_widget)
Overall_Layout = QtGui.QGridLayout(central_widget)
Play_Button = QtGui.QPushButton(QtGui.QIcon("images/PLAY.bmp"), "PLAY")
Overall_Layout.addWidget(Play_Button,1,2)
Overall_Layout.addWidget(Play_Button,2,2)
########################################################
On the other hand if you inherit from QMainWindow you must call the QMainWindow constructor, but in code you call QWidget, so you must modify it to:
class MainWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
Or
class MainWindow(QtGui.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()

Can I make a groupbox outside of a scroll area?

I have a QGroupBox with a title '123'. Inside the QGroupBox, there should be a QScrollArea. That means that the title '123' of QGrouBox should be outside of the QScrollArea.
My sample codes are as below.
import sys
import PyQt4
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class Example(QWidget):
def __init__(self, parent = None):
super().__init__()
btn = QPushButton('button')
scroll = QScrollArea()
scroll.setWidgetResizable(True)
scroll.setWidget(btn)
groupbox = QGroupBox('123')
groupbox.setLayout(scroll)
self.show()
def main():
app = QApplication(sys.argv)
main = Example()
main.show()
sys.exit(app.exec_())
As you can see above, now it returns TypeError: setLayout(self, QLayout): argument 1 has unexpected type 'QScrollArea'.
I'm just wondering if this is achievable? Thanks!!
When you want to add the content to a QGroupBox you must do through a layout that contains the necessary widgets, in this case as it is only a widget we can use any layout, and in this layout we add the widget that this case is the QScrollArea as sample then:
class Example(QWidget):
def __init__(self, parent = None):
super().__init__()
self.setLayout(QVBoxLayout())
btn = QPushButton('button')
scroll = QScrollArea()
scroll.setWidgetResizable(True)
scroll.setWidget(btn)
groupbox = QGroupBox('123', self)
groupbox.setLayout(QVBoxLayout())
groupbox.layout().addWidget(scroll)
self.layout().addWidget(groupbox)
Screenshot:

pyqt4 already has a layout. How to 'detect' it or change?

I'm trying to set a layout manager. But getting the message:
QLayout: Attempting to add QLayout "" to Window "", which already has a layout
How can I change or detect which type the layout is? I'd like to use the boxlayout as it seems to be prefered.
import sys
from PyQt4 import QtGui as qt
class Window(qt.QMainWindow):
def __init__(self):
super(Window, self).__init__()
#Lav widgets
self.CreateWidgets()
def CreateWidgets(self):
btn = qt.QPushButton("Fetch", self)
btn.clicked.connect(self.GetData)
self.layout = qt.QVBoxLayout(self)
self.setGeometry(560, 240, 800, 600)
self.setWindowTitle("We do not sow")
self.show()
def GetData(self):
print("Hello World!")
app = qt.QApplication(sys.argv)
w = Window()
sys.exit(app.exec_())
The QMainWindow class has built-in support for toolbars and dock-widgets, and a menubar and statusbar - so it has to have a fixed layout. Therefore, rather than adding child widgets to the main window itself, you must set its central widget, and then add the child widgets to that:
def CreateWidgets(self):
btn = qt.QPushButton("Fetch", self)
btn.clicked.connect(self.GetData)
widget = qt.QWidget(self)
layout = qt.QVBoxLayout(widget)
layout.addWidget(btn)
self.setCentralWidget(widget)
self.setGeometry(560, 240, 800, 600)
self.setWindowTitle("We do not sow")

Python PyQt4: Single child window

I have a simple PyQt4 example.
When run, it displays a QMainWindow with a button.
If you click the button, then a second QMainWindow is created.
If you click it again, you get 2 second windows.
What is an elegant and simple way to prevent more than 1 second window in this example?
import sys
from PyQt4.QtGui import *
class win2(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self,parent)
layout = QVBoxLayout()
label = QLabel(self)
label.setText('This is win2')
layout.addWidget(label)
self.adjustSize()
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
layout = QVBoxLayout()
button1 = QPushButton("win2", self)
layout.addWidget(button1)
button1.clicked.connect(self.showwin2)
def showwin2(self):
w2 = win2(self)
w2.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
sys.exit(app.exec_())
Your Function creates a new instance of the class win2 each time the button is pressed. To Supress this behavior only call the show and raise_ functions instead of creating a new instance.
I would create the class as follows, and only use the button to 'show' the window. Tested and works as intended. Also consider using self when assigning your variables so they can be accessed throughout the class instance.
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
layout = QVBoxLayout()
button1 = QPushButton("win2", self)
layout.addWidget(button1)
button1.clicked.connect(self.showwin2)
self.w2 = win2(self)
def showwin2(self):
self.w2.show()
self.w2.raise_()

Categories