QStackedLayout shows empty window for a few moments - python

In this example, as the main window, I use a QWidget that contains a QStackedLayout and a QPushButton to change the current widget to a QStackedLayout.
from PySide6.QtWidgets import QFrame, QWidget, QApplication, QVBoxLayout, QStackedLayout, QPushButton
from PySide6.QtCore import Qt
class ColorWidget(QFrame):
def __init__(self, color):
super(ColorWidget, self).__init__()
self.setFixedSize(200, 200)
self.setStyleSheet(f"background-color: {color}; border-radius: 6px;")
# Some widget. In this case, just a colored background.
class MainWidget(QWidget):
def __init__(self):
super(MainWidget, self).__init__()
self.current_widget = False
layout = QStackedLayout()
layout.addWidget(ColorWidget("red"))
layout.addWidget(ColorWidget("yellow"))
layout.setCurrentIndex(0)
self.setLayout(layout)
# Main widget. Contains 2 colored widgets.
def change_visible_widget(self):
self.current_widget = not self.current_widget
self.layout().setCurrentIndex(int(self.current_widget))
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowFlag(Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
# no frame, no background
layout = QVBoxLayout()
main_widget = MainWidget()
button = QPushButton("change")
button.clicked.connect(main_widget.change_visible_widget)
# button to change QStackedLayout index in Main Widget
layout.addWidget(main_widget)
layout.addWidget(button)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication()
win = MainWindow()
win.show()
app.exec()
The problem is that when the program starts, an empty window appears for a few moments.
By trial and error, I realized that this is because of the QStackedLayout and the number of windows that appear is equal to the number of created QStackedLayout (in this case it is 1).
How can this be fixed?

Just add self to layout = QStackedLayout():
from PySide6.QtWidgets import QFrame, QWidget, QApplication, QVBoxLayout, QStackedLayout, QPushButton
from PySide6.QtCore import Qt
class ColorWidget(QFrame):
def __init__(self, color):
super(ColorWidget, self).__init__()
self.setFixedSize(200, 200)
self.setStyleSheet(f"background-color: {color}; border-radius: 6px;")
# Some widget. In this case, just a colored background.
class MainWidget(QWidget):
def __init__(self):
super(MainWidget, self).__init__()
self.current_widget = False
layout = QStackedLayout(self)
layout.addWidget(ColorWidget("red"))
layout.addWidget(ColorWidget("yellow"))
layout.setCurrentIndex(0)
# Main widget. Contains 2 colored widgets.
def change_visible_widget(self):
self.current_widget = not self.current_widget
self.layout().setCurrentIndex(int(self.current_widget))
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowFlag(Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
# no frame, no background
layout = QVBoxLayout()
main_widget = MainWidget()
button = QPushButton("change")
button.clicked.connect(main_widget.change_visible_widget)
# button to change QStackedLayout index in Main Widget
layout.addWidget(main_widget)
layout.addWidget(button)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication()
win = MainWindow()
win.show()
app.exec()

Related

How to transfer items from QListWidget based in one window to another QListWidget based in another window?

That being said, I would like to be able to transfer my items from QListWidget based in one window to another.
The code below allows me to transfer one item at a time,
but I am struggling to think of a way to transfer multiple items
at one time.
(Code below is from an example I found and have altered.)
from PyQt5.QtWidgets import (
QApplication,
QMainWindow,
QDialog,
QWidget,
QVBoxLayout,
QLineEdit,
QLabel,
QPushButton,
QListWidget,
QAbstractItemView
)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.user_input = QListWidget()
self.user_input.addItem("2")
self.user_input.addItem("3")
self.populate()
self.show()
self.user_input.setSelectionMode(QAbstractItemView.ExtendedSelection)
def populate(self):
widgets = [QLabel("Insert a number"), self.user_input]
centralWidget = self.group_widgets(widgets)
self.setCentralWidget(centralWidget)
def group_widgets(self, widgets):
parentWidget = QWidget()
layout = QVBoxLayout()
for widget in widgets: layout.addWidget(widget)
parentWidget.setLayout(layout)
return parentWidget
def when_input(self, function):
#self.user_input.textChanged.connect(function)
self.user_input.itemClicked.connect(self.printItemText)
self.user_input.itemClicked.connect(function)
def printItemText(self):
items = self.user_input.selectedItems()
x = []
for i in range(len(items)):
x.append(str(self.user_input.selectedItems()[i].text()))
print (x)
class Dialog(QDialog):
def __init__(self):
super().__init__()
self.user_input = QListWidget()
self.relay_sum = None # function to relay result of addition
self.populate()
self.show()
def populate(self):
widgets = self.get_widgets()
layout = self.get_layout(widgets)
self.setLayout(layout)
def get_widgets(self):
widgets = [
QLabel("Inserted number"),
self.user_input,
]
return widgets
def get_layout(self, widgets):
layout = QVBoxLayout()
for widget in widgets: layout.addWidget(widget)
return layout
def main():
app = QApplication([])
mainWindow = MainWindow()
dialog = Dialog()
mainWindow.when_input(lambda text: dialog.user_input.addItem(str(text.text())))
app.exec_()
if __name__ == "__main__":
main()
When an item is clicked it is also selected so just use the last feature.
One possible solution is to create a new token that transports the cloned items from the selected items, and then add it to the other QListWidget.
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import (
QAbstractItemView,
QApplication,
QDialog,
QLabel,
QListWidget,
QMainWindow,
QVBoxLayout,
QWidget,
)
class MainWindow(QMainWindow):
custom_signal = pyqtSignal(list)
def __init__(self):
super().__init__()
self.user_input = QListWidget(selectionMode=QAbstractItemView.ExtendedSelection)
self.user_input.addItem("2")
self.user_input.addItem("3")
self.populate()
self.user_input.itemSelectionChanged.connect(self.handle_selection_changed)
def populate(self):
widgets = [QLabel("Insert a number"), self.user_input]
centralWidget = self.group_widgets(widgets)
self.setCentralWidget(centralWidget)
def group_widgets(self, widgets):
parentWidget = QWidget()
layout = QVBoxLayout(parentWidget)
for widget in widgets:
layout.addWidget(widget)
return parentWidget
def handle_selection_changed(self):
items = []
for item in self.user_input.selectedItems():
items.append(item.clone())
self.custom_signal.emit(items)
class Dialog(QDialog):
def __init__(self):
super().__init__()
self.user_input = QListWidget()
self.populate()
def populate(self):
widgets = self.get_widgets()
layout = self.get_layout(widgets)
self.setLayout(layout)
def get_widgets(self):
widgets = [
QLabel("Inserted number"),
self.user_input,
]
return widgets
def get_layout(self, widgets):
layout = QVBoxLayout()
for widget in widgets:
layout.addWidget(widget)
return layout
def add_items(self, items):
for item in items:
self.user_input.addItem(item)
def main():
app = QApplication([])
mainWindow = MainWindow()
mainWindow.show()
dialog = Dialog()
dialog.show()
mainWindow.custom_signal.connect(dialog.add_items)
app.exec_()
if __name__ == "__main__":
main()

How to have signals and slots connect across classes?

I am trying to make a basic text editor with a toolbar, sidebar, and textbox. My program needs to use a QPushButton (which is in my 'toolbar' class) to make the text in my QTextEdit bold (in my TextEdit class). Here's an example snippet of code:
import sys
from PyQt5.QtWidgets import QPushButton, QTextEdit, QWidget, QMainWindow
from PyQt5.Qt import Qt, QApplication, QVBoxLayout, QHBoxLayout, QFrame, QFont
class ToolBar(QWidget):
def __init__(self):
super().__init__()
layout = QHBoxLayout()
self.btn = QPushButton(self, text="Bold")
layout.addWidget(self.btn)
self.italic = QPushButton(self, text="Italic")
layout.addWidget(self.italic)
t = TextEdit()
# This is the line that isn't working
self.btn.clicked.connect(lambda: t.set_bold())
# I've tried this without the lambda, and also with 'TextEdit.set_bold' but they didn't work
# It would also be nice to do the same for the italic buttons and other buttons in my toolbar
self.setLayout(layout)
class TextEdit(QWidget):
def __init__(self):
super().__init__()
self.textEdit = QTextEdit(self)
# self.set_bold() <-- If I were to run this, then the text box would become bold, so I know that it's not an error with the function
def set_bold(self):
# print("function activated") <-- This statement shows that the function is indeed executing
self.font = QFont("Helvetica", 14)
self.font.setBold(True)
self.textEdit.setFont(self.font)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
central_widget = QFrame()
layout = QVBoxLayout()
self.boldButton = ToolBar()
layout.addWidget(self.boldButton)
self.textBox = TextEdit()
layout.addWidget(self.textBox)
central_widget.setLayout(layout)
self.setCentralWidget(central_widget)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
I tried putting a print statement to confirm that the function is executing, which it is. I don't get any error messages so I can't seem to figure out what to do.
The connection must occur where the objects have a common scope, in this case within the MainWindow class.
class ToolBar(QWidget):
def __init__(self):
super().__init__()
self.bold_button = QPushButton(text="Bold")
self.italic_button = QPushButton(text="Italic")
layout = QHBoxLayout(self)
layout.addWidget(self.bold_button)
layout.addWidget(self.italic_button)
class TextEdit(QWidget):
def __init__(self):
super().__init__()
self.textEdit = QTextEdit(self)
def set_bold(self):
font = QFont("Helvetica", 14)
font.setBold(True)
self.textEdit.setFont(font)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.toolbar = ToolBar()
self.textBox = TextEdit()
central_widget = QFrame()
layout = QVBoxLayout(central_widget)
layout.addWidget(self.toolbar)
layout.addWidget(self.textBox)
self.setCentralWidget(central_widget)
self.toolbar.bold_button.clicked.connect(self.textBox.set_bold)

Share attribute between two classes "QWidget"

I'm trying to "send" the attribute from a QWidget class to another.
In the example below, I'm trying to set the text of the QLineEdit "self.edit" belonging to the class "Widget1" as text of the QLabel "self.label" belonging to the class "Widget2".
This attempt is made in the function "setLabel".
The part that I cannot figure out is "Widget2.label.setText(text)"
Having a class in a class in a function... I'm a little bit confused how to achieve that...
import sys
from PySide2.QtWidgets import (QApplication, QHBoxLayout, QVBoxLayout, QWidget, QPushButton, QLabel, QLineEdit)
class Main_UI(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
layout = QVBoxLayout()
widget1 = Widget1()
widget2 = Widget2()
layout.addWidget(widget1)
layout.addWidget(widget2)
self.setLayout(layout)
self.show()
class Widget1(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
layout = QHBoxLayout()
self.edit = QLineEdit("")
button = QPushButton("Set value")
button.clicked.connect(self.setLabel)
layout.addWidget(self.edit)
layout.addWidget(button)
self.setLayout(layout)
def setLabel(self):
text = self.edit.text()
Widget2.label.setText(text)
class Widget2(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
layout = QHBoxLayout()
self.label = QLabel("")
layout.addWidget(self.label)
self.setLayout(layout)
def main():
app = QApplication(sys.argv)
ex = Main_UI()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Any help would be appreciated, and if my example or explanations are not clear, I'll provide further explanations.
You can do this with a custom signal.
import sys
from PyQt5.QtWidgets import (QApplication, QHBoxLayout, QVBoxLayout, QWidget, QPushButton, QLabel, QLineEdit)
from PyQt5 import QtCore
class Main_UI(QWidget):
def __init__(self, parent=None):
super(Main_UI, self).__init__(parent)
self.initUI()
def initUI(self):
layout = QVBoxLayout()
widget1 = Widget1()
widget2 = Widget2()
layout.addWidget(widget1)
layout.addWidget(widget2)
self.setLayout(layout)
widget1.button_signal.connect(widget2.label.setText) # Connecting the label to the custom signal.
self.show()
class Widget1(QWidget):
button_signal = QtCore.pyqtSignal(str) # Creating a signal.
def __init__(self, parent=None):
super(Widget1, self).__init__(parent)
self.initUI()
def initUI(self):
layout = QHBoxLayout()
self.edit = QLineEdit("")
button = QPushButton("Set value")
button.clicked.connect(self.setLabel)
layout.addWidget(self.edit)
layout.addWidget(button)
self.setLayout(layout)
def setLabel(self):
"""Emit button signal with text.
This could have been solved with a lambda.
"""
self.button_signal.emit(self.edit.text()) # Emitting Signal.
class Widget2(QWidget):
def __init__(self, parent=None):
super(Widget2, self).__init__(parent)
self.initUI()
def initUI(self):
layout = QHBoxLayout()
self.label = QLabel("")
layout.addWidget(self.label)
self.setLayout(layout)
def main():
app = QApplication(sys.argv)
ex = Main_UI()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Docs: https://doc.qt.io/qt-5/signalsandslots.html

How to create a new window with button click [duplicate]

This question already has an answer here:
How to open a window with a click of a button from another window using PyQt?
(1 answer)
Closed 3 years ago.
I want to create a new window when a button is clicked. I will later have windows be created dynamically depending on inputted data. But I want to start simple first.
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QPushButton, QGridLayout, QWidget
class MyWindow(QtWidgets.QMainWindow, QPushButton):
def __init__(self):
super(MyWindow, self).__init__()
centralWidget = QWidget()
self.setCentralWidget(centralWidget)
self.setWindowTitle("ASSET")
self.Button = QPushButton('Action',self)
self.Button.clicked.connect(self.Action)
self.layout = QGridLayout(centralWidget)
self.layout.addWidget(self.Button)
def Action(self):
pass
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())
You can create another QMainWindow() and when the button is clicked, activate the show() method
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QPushButton, QGridLayout, QWidget, QLabel
class NewWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(NewWindow, self).__init__(parent)
self.label = QLabel('New Window!')
centralWidget = QWidget()
self.setCentralWidget(centralWidget)
self.layout = QGridLayout(centralWidget)
self.layout.addWidget(self.label)
class MyWindow(QtWidgets.QMainWindow, QPushButton):
def __init__(self):
super(MyWindow, self).__init__()
centralWidget = QWidget()
self.setCentralWidget(centralWidget)
self.setWindowTitle("ASSET")
self.Button = QPushButton('Action',self)
self.Button.clicked.connect(self.Action)
self.layout = QGridLayout(centralWidget)
self.layout.addWidget(self.Button)
self.new_window = NewWindow(self)
def Action(self):
self.new_window.show()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())

PyQt: How to create a scrollable window

I think it should be much easier to create a scrollable window in PyQt.
I have a list of labels that goes out of the window and I would like to scroll down to view them. At the moment the code does not give me an error, but the window just doesn't appear:
class Example(QWidget):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
lbl_arr = makeLabelArr()
for i in range(1,8):
qb = lbl_arr[i]
# qb.setFixedWidth(300)
layout.addWidget(qb)
layout.setAlignment(Qt.AlignTop)
scroll = QScrollArea()
scroll.setWidget(self)
scroll.setWidgetResizable(True)
scroll.setFixedHeight(400)
layout.addWidget(scroll)
self.setLayout(layout)
self.setGeometry(0, 0, 600, 220)
self.setWindowTitle('SnP watchlist')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
#print(QDesktopWidget().availableGeometry())
ex = Example()
sys.exit(app.exec_())
Make the window itself a QScrollArea, like this:
class Window(QScrollArea):
def __init__(self):
super(Window, self).__init__()
widget = QWidget()
layout = QVBoxLayout(widget)
layout.setAlignment(Qt.AlignTop)
for index in range(100):
layout.addWidget(QLabel('Label %02d' % index))
self.setWidget(widget)
self.setWidgetResizable(True)
There is an example here: https://www.learnpyqt.com/tutorials/qscrollarea/
from PyQt5.QtWidgets import (QWidget, QSlider, QLineEdit, QLabel, QPushButton, QScrollArea,QApplication,
QHBoxLayout, QVBoxLayout, QMainWindow)
from PyQt5.QtCore import Qt, QSize
from PyQt5 import QtWidgets, uic
import sys
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.scroll = QScrollArea() # Scroll Area which contains the widgets, set as the centralWidget
self.widget = QWidget() # Widget that contains the collection of Vertical Box
self.vbox = QVBoxLayout() # The Vertical Box that contains the Horizontal Boxes of labels and buttons
for i in range(1,50):
object = QLabel("TextLabel: "+str(i))
self.vbox.addWidget(object)
self.widget.setLayout(self.vbox)
#Scroll Area Properties
self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.scroll.setWidgetResizable(True)
self.scroll.setWidget(self.widget)
self.setCentralWidget(self.scroll)
self.setGeometry(600, 100, 1000, 900)
self.setWindowTitle('Scroll Area Demonstration')
self.show()
return
def main():
app = QtWidgets.QApplication(sys.argv)
main = MainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
You should set layout after adding the scroll bar widget.
class Example(QWidget):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
lbl_arr = makeArrayOfLabelsHTML()
for i in range(1,8):
qb = lbl_arr[i]
layout.addWidget(qb)
layout.setAlignment(Qt.AlignTop)
scroll = QScrollArea()
scroll.setWidget(self)
scroll.setWidgetResizable(True)
scroll.setFixedHeight(400)
layout.addWidget(scroll)
# set layout after adding scroll bar
self.setLayout(layout)
self.setGeometry(0, 0, 600, 220)
self.setWindowTitle('SnP watchlist')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
#print(QDesktopWidget().availableGeometry())
ex = Example()
sys.exit(app.exec_())

Categories

Resources