#๐ what is pyside6 how do i use it?
244 messages ยท Page 1 of 1 (latest)
@prime beacon
Remember to:
- Ask your Python question, not if you can ask or if there's an expert who can help.
- Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
- Explain what you expect to happen and what actually happens.
:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.
definitely don't use designer
oh ok
pyside doesn't necessarily have the same concept as pack/grid that tkinter does
it uses layouts to hold widgets
QVBoxLayout will arrange things vertically. QHBoxLayout will arrange things horizontally
there's also QGridLayout if you want a grid of things
The equivalent of a tkinter frame would be QWidget
it's just an empty container widget that can have its own layout
how do i import it? pyside is not found
there's also QFrame which is similar, but it has extra styling options (you can emboss, draw boxes around it, etc)
then QGroupBox is just a widget that has a box around it and a label
you import from PySide6
there's 3 libraries you'll usually want to import
from PySide6 import QtWidgets, QtGui, QtCore
QtWidgets is where you can find all your widgets. Buttons, sliders, checkboxes, frames, etc
QtGui is more about widget modification. Things like fonts, colours, painting tools, etc
i didnt think capital matters thats the problem
QtCore is helped classes. Things like measuring sizes, getting the cursor
it doesn't for pip install, but it definitely does when importing
from PySide6 import QtWidgets, QtCore, QtGui
class Window(QtWidgets.QDialog):
pass
app = QtWidgets.QApplication()
win = Window()
win.show()
app.exec()
this is the basic setup for a pyside ui
you always need to initialize your QApplication first
then create whatever you want to display
then exec your application
ok so as a start how do i make my menu?
it has 2 labels and 2 buttons centered and lined up verticaly
can you show what that looks like?
lower 2 are the buttons
ok, so you can see that everything here is arranged vertically, so a QVBoxLayout would be perfect
also spacings with the buttons and teexts haveing bigger spacing
but we also know that this will all need to removed after a selection is made, so we'll likely want to make it into its own widget (like a tkinter frame)
we can make this an entirely separate class if we want (and I recommend it)
class WelcomeMenu(QtWidgets.QWidget):
i was planning to put it even in a sep file
class WelcomeMenu(QtWidgets.QWidget):
def __init__(self):
super().__init__()
main_layout = QtWidgets.QVBoxLayout()
self.setLayout(main_layout)
here's the basic setup for a custom qwidget
we create a layout, then set it to self
now we can start adding widgets to that layout
class WelcomeMenu(QtWidgets.QWidget):
def __init__(self):
super().__init__()
main_layout = QtWidgets.QVBoxLayout()
self.setLayout(main_layout)
title_label = QtWidgets.QLabel("Welcome!")
subtitle_label = QtWidgets.Label("Select an option")
option_1_btn = QtWidgets.QPushButton("Option 1")
option_2_btn = QtWidgets.QPushButton("Option 2")
I always start by making the widgets that I know I'll need
then we can add them to the layout in the order that we want to display them
adding to layout is like grid/pack in tk?
main_layout.addWidget(title_label)
main_layout.addWidget(subtitle_label)
main_layout.addWidget(option_1_btn)
main_layout.addWidget(option_2_btn)
yup exactly
it's what actually tells the layout to display that widget
so this is nearly done, but you now need to add this widget to the main window
class Window(QtWidgets.QDialog):
def __init__(self):
super().__init__()
main_layout = QtWidgets.QVBoxLayout()
self.setLayout(main_layout)
we do basically the same thing for the Window class
a QDialog is basically a QWidget that acts as a window
self.welcome_menu_widget = WelcomeMenu()
main_layout.addWidget(self.welcome_menu_widget)
then all we need to do is make an instance of our WelcomeMenu and add it
I used an attribute for the welcome menu widget because we know we'll need to access it later to remove it
so it's not very exciting yet, but everything is in place!
whoops, they both say option 1
to set the command of a button like you would in tkinter, pyside uses something called "signals and slots"
why do i need a box why cant i put it straight into the window?
Because once you click a button, you want to remove all of these and display something else, yes?
yes
It's a lot easier to remove one widget than it is all of the ones you put into your menu
an other premade widget containing the main functionalyty
also having it as a separate class makes your code less cluttered
we can focus on all of our main menu logic and styling in the main menu class
and when we want to remove the menu, we only need to remove that one widget
i know but why did we add a layout to the main and add the menu to that layout
when the menu already is a layout
layouts are what hold our widgets
even though we're only displaying 1 thing
we still want a layout
plus we'll reuse that layout for other things once we remove the menu
than u forgot to make it an attr?
ahh yeah, main_layout should be an attr
from PySide6 import QtWidgets, QtCore, QtGui
from Menu.UI.menu_ui import Menu
class Window(QtWidgets.QDialog):
def __init__(self):
super().__init__()
self.main_layout = QtWidgets.QVBoxLayout()
self.setLayout(self.main_layout)
self.menu = Menu()
self.main_layout.addWidget(self.menu)
app = QtWidgets.QApplication()
win = Window()
win.show()
app.exec()
why does this instantly exit with no error?
what's in your Menu file?
from PySide6 import QtWidgets, QtCore, QtGui
class Menu(QtWidgets.QWidget):
def __init__(self) -> None:
super().__init__()
main_layout = QtWidgets.QVBoxLayout()
self.setLayout(main_layout)
title_label = QtWidgets.QLabel("State Machine Simulator!")
subtitle_label = QtWidgets.QLabel("Select an option")
option_1_btn = QtWidgets.QPushButton("Undeterministic Finite Incomplete State Machine")
option_2_btn = QtWidgets.QPushButton("Deterministic Finite Incomplete Stack State Machine")
main_layout.addWidget(title_label)
main_layout.addWidget(subtitle_label)
main_layout.addWidget(option_1_btn)
main_layout.addWidget(option_2_btn)
ah i may have failed to save something it works now
how do i center all of the widgets in the menu?
ok so layout alignment takes a bit of getting used to
but it's pretty straightforward once you understand a few quirks
also i want them to be pushed together in the midle
so by default, a layout will evenly space its widgets within
i seen that
wait why the buttons stick?
buttons may expand horizontal, but not vertical
because QLabel has a size policy that allows for vertical resizing, they get priority
that causes the buttons to "stick"
we could change this in a number of ways
we could tell buttons to resize vertically
we could tell labels to stop resizing vertically
ah it doesnt space evenly in the sense that thats not space in between
each widget is technically placed inside a "QLayoutItem" before being added to the layout
if the widget is not capable of resizing, the qlayoutitem will resize instead
but again it depends on "size hints" and "size policy"
honestly a lot of this isn't stuff you need to worry about for the moment, there's some simple workarounds
the simplest one is to use a "stretcher"
it has high priority and automatically fills out the space
we can add a stretcher before and after we add our widgets
it will give us this result as the window scales up vertically
main_layout.addStretch()
main_layout.addWidget(title_label)
main_layout.addWidget(subtitle_label)
main_layout.addWidget(option_1_btn)
main_layout.addWidget(option_2_btn)
main_layout.addStretch()
plus i want to center them horizontaly too
ok, so currently, the labels technically are centered, but the text within the label is not centered
if we display a box around our qlabel, we can see what's actually happening
oh
we can easily set an alignment on our label though
title_label.setAlignment(QtCore.Qt.AlignCenter)
also the buttons streching looks bad how do i change that size policy or how does that work?
ok so every widget has what's called a "Size Hint"
this is what the widget determines how much space it should take up
the size policy has a relationship with the size hint
it might be a bit counter intuitive
but a size policy of "Minimum" tells a widget that its size hint is the smallest size that the widget is allowed to be
QtCore.Qt.AlignCenter seems to not exist
Are you importing QtCore?
yes
it absolutely should exist. Check your capitalization
the AlingmentCenter is the part thats missing
Yes
VS also has that problem
ok, so to actually set the size policy, we just use setSizePolicy
you wrote Aling
it's Align
option_1_btn.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
This is how we set the size policy
we have to give it two values. The first one is the policy for horizontal and the 2nd is for vertical
Fixed is the easiest option for now. It basically says "Use the size hint" and never grow or shrink
you'll need to center it though
To center just a specific widget in a layout, you can set the alignment during addWidget
now everything is nice and centered
you could actually change this to inherit from QFrame instead of QWidget which would give you some style options
now it has a nice box
where do i find what i need to pass to alingment?
main_layout.addStretch()
main_layout.addWidget(title_label)
main_layout.addWidget(subtitle_label)
main_layout.addWidget(option_1_btn, alignment=QtCore.Qt.AlignCenter)
main_layout.addWidget(option_2_btn, alignment=QtCore.Qt.AlignCenter)
main_layout.addStretch()
pretty much all alignment options accept the Qt.Align flags
There's a ton of useful enums in Qt, so most people will actually do from PySide6.QtCore import Qt
i got something to do but than ill come back and next is the Undeterministic machines ui
next i want to make something like this
i seen theres a scrollable widget so i want that and changing amount of buttons in it
i want a big are where i can detect clicks to the right + i may want to add some text on the drawing are at random spots
what widget should i use for my drawing area?
and how do i make it so the earlyet 2 buttons are at the bottom but the rest at the top of the scroll box?
what is that scrollbox called?
you can use addStretch between the buttons to push the rest of the buttons to the top or bottom
QScrollArea
It's a bit weird though
you have to set a widget to it
and that widget should have a layout
i want it to be at the end of the list i mean
so there's always like an "add new" button kinda thing?
yes
instead of addWidget, you can insertWidget instead
but maybe ill auto add it when the user uses a new letter
so that you can insert new widgets above the "add new" button
from PySide6 import QtWidgets, QtCore, QtGui
class Window(QtWidgets.QDialog):
def __init__(self):
super().__init__()
self.main_layout = QtWidgets.QVBoxLayout()
self.setLayout(self.main_layout)
add_new_btn = QtWidgets.QPushButton("Add New +")
self.main_layout.addWidget(add_new_btn)
add_new_btn.clicked.connect(self.on_add_new_clicked)
def on_add_new_clicked(self):
btn = QtWidgets.QPushButton("Button")
self.main_layout.insertWidget(self.main_layout.count() - 1, btn)
app = QtWidgets.QApplication()
win = Window()
win.show()
app.exec()
try running this code
you'll notice that all the widgets end up spaced though
you can set the entire alignment of the layout to AlignTop though to solve this
once you set up your scroll area, you'll likely end up with something like this which makes it a bit of a pain to see the Add New btn
I would have it outside of the scroll area
I actually have my own similar UI
It's a pretty small button, but I use the + in the corner to add new buttons (or new tabs)
but I can also right click in any empty spot in the scroll area to add new buttons too
it just gives me a menu popup like this
i think the popup is too much for me bc all u need is to name it
does the scroll area also need a layout?
the scroll area needs a widget, and that widget needs a scroll area
it can get a bit confusing with this one
self.btn_scroll_area = QtWidgets.QScrollArea()
self.btn_scroll_area.setWidgetResizable(True)
self.btn_scroll_wdg = QtWidgets.QWidget()
self.btn_scroll_layout = QtWidgets.QVBoxLayout()
self.btn_scroll_layout.setAlignment(QtCore.Qt.AlignTop)
self.btn_scroll_wdg.setLayout(self.btn_scroll_layout)
self.btn_scroll_area.setWidget(self.btn_scroll_wdg)
self.main_layout.addWidget(self.btn_scroll_area)
this is what I used
widget as in anything i put in it?
the widget is a single widget that the scroll area will display
so if you had a giant image for example, you could display that in a scroll area
this is fine if I just want to display a single widget
but if I want to display a widget that also contains other widgets, then I need something that can hold a layout
self.scroll = QtWidgets.QScrollArea()
img = QtWidgets.QLabel()
img.setPixmap(QtGui.QPixmap('mountains.png'))
self.scroll.setWidget(img)
so i add a frame? or layout?
look here
I create a widget
I create a layout
I setLayout that layout to that widget
then I setWidget that new widget to the scroll area
how do i remove the last widget added to a layout?
It depends. Usually I just destroy the widget and the layout will clean it self up
widget.deleteLater()
but i may want to keep the same instance of the menu and other parts
You can hide the visibility of a widget then with setVisibility
whats the diff between an item and a widget?
Layouts and some other widgets display their data as items
QListWidget for example displays items
Even though you addWidget to a layout, it ultimately creates layout items
why is this?
def Undet(self):
self.main_layout.removeItem(self.main_layout.itemAt(0))
self.main_layout.addWidget(self.undet)
so this should work right?
oh
Yes
Another option is using a Stack Layout instead
It's useful when you want different screens to display to a user
why doesnt my scroll apier?
class Undet(QtWidgets.QFrame):
def __init__(self, master) -> None:
super().__init__()
self.master = master
main_layout = QtWidgets.QHBoxLayout()
self.setLayout(main_layout)
self.sandbox = QtWidgets
self.scrollbox = buttons_scroll()
main_layout.addWidget(self.scrollbox)
class buttons_scroll(QtWidgets.QScrollArea):
def __init__(self) -> None:
super().__init__()
self.setWidgetResizable(True)
self.area = QtWidgets.QWidget()
self.area_layout = QtWidgets.QVBoxLayout()
self.area_layout.setAlignment(QtCore.Qt.AlignTop)
self.add_new = QtWidgets.QPushButton(text=" + ")
self.add_new.clicked.connect(lambda: self.add_letter("x"))
self.buttons: list[QtWidgets.QPushButton] = []
self.area_layout.addWidget(self.add_new)
def add_letter(self, letter: str) -> None:
self.buttons.append(QtWidgets.QPushButton(text=letter))
self.buttons[-1].clicked.connect(self.make_callback(letter))
self.area_layout.insertWidget()
def make_callback(self, letter: str):
def callback():
print(letter)
return callback
Can you send the full code?
main
from PySide6 import QtWidgets, QtCore, QtGui
from Menu.UI.menu_ui import Menu
from Undet.UI.undet_ui import Undet
class Window(QtWidgets.QDialog):
def __init__(self):
super().__init__()
self.main_layout = QtWidgets.QVBoxLayout()
self.setLayout(self.main_layout)
self.menu = Menu(self)
self.undet = Undet(self)
self.main_layout.addWidget(self.menu)
def Undet(self):
self.main_layout.removeItem(self.main_layout.itemAt(0))
self.main_layout.addWidget(self.undet)
app = QtWidgets.QApplication()
win = Window()
win.show()
app.exec()
class Menu(QtWidgets.QFrame):
def __init__(self, master) -> None:
super().__init__()
self.master = master
main_layout = QtWidgets.QVBoxLayout()
self.setLayout(main_layout)
title_label = QtWidgets.QLabel("State Machine Simulator!")
title_label.setAlignment(QtCore.Qt.AlignCenter)
subtitle_label = QtWidgets.QLabel("Select an option")
subtitle_label.setAlignment(QtCore.Qt.AlignCenter)
option_1_btn = QtWidgets.QPushButton("Undeterministic Finite Incomplete State Machine")
option_1_btn.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
option_1_btn.clicked.connect(master.Undet)
option_2_btn = QtWidgets.QPushButton("Deterministic Finite Incomplete Stack State Machine")
option_2_btn.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
main_layout.addStretch()
main_layout.addWidget(title_label)
main_layout.addWidget(subtitle_label)
main_layout.addWidget(option_1_btn, alignment=QtCore.Qt.AlignCenter)
main_layout.addWidget(option_2_btn, alignment=QtCore.Qt.AlignCenter)
main_layout.addStretch()
```menu
you never did self.setWidget(self.area) in your buttons_scroll class
make sure you name classes with capitalization or it can be hard to follow
class ButtonsScroll
def make_callback(self, letter: str):
def callback():
print(letter)
return callback
this is also unnecessary
just call the method directly
ahh, it has an argument
use partial
from functools import partial
self.buttons[-1].clicked.connect(partial(letter, self.on_btn_clicked))
it will create the callbacks just for now i added a print to see if it works
This help channel has been closed and it's no longer possible to send messages here. If your question wasn't answered, feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.