ObjectName of a button when clicked in PySide6 [duplicate] - pyside

This question already has answers here:
PyQT button clicked name
(2 answers)
PyQt: Getting which button called a specific function
(2 answers)
Closed 2 months ago.
In PySide6, how to identify the objectName of a button when clicked?
I have a screen with several buttons and I need to identify the objectName of the clicked button.

If you need all buttons connect to same slot, just use self.sender() to identify which button is clicked. Easy example as below, you can copy it and run for test, enjoy it~
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
import sys
class Main(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.ui = Ui_MyWidget_TestButton()
self.ui.setupUi(self)
self.ui.pushButton_A.clicked.connect(self.button_clicked_slot)
self.ui.pushButton_B.clicked.connect(self.button_clicked_slot)
def button_clicked_slot(self, clicked):
# get clicked button and do anything you need.
sender = self.sender()
self.ui.label.setText(f"{sender.objectName()} is clicked ~")
class Ui_MyWidget_TestButton(object):
def setupUi(self, MyWidget_TestButton):
if not MyWidget_TestButton.objectName():
MyWidget_TestButton.setObjectName(u"MyWidget_TestButton")
MyWidget_TestButton.resize(369, 178)
self.pushButton_A = QPushButton(MyWidget_TestButton)
self.pushButton_A.setObjectName(u"pushButton_A")
self.pushButton_A.setGeometry(QRect(80, 70, 75, 24))
self.pushButton_B = QPushButton(MyWidget_TestButton)
self.pushButton_B.setObjectName(u"pushButton_B")
self.pushButton_B.setGeometry(QRect(210, 70, 75, 24))
self.label = QLabel(MyWidget_TestButton)
self.label.setObjectName(u"label")
self.label.setGeometry(QRect(100, 130, 171, 20))
self.label.setStyleSheet(u"color: rgb(0, 85, 255);")
self.retranslateUi(MyWidget_TestButton)
QMetaObject.connectSlotsByName(MyWidget_TestButton)
# setupUi
def retranslateUi(self, MyWidget_TestButton):
MyWidget_TestButton.setWindowTitle(QCoreApplication.translate("MyWidget_TestButton", u"TestButton", None))
self.pushButton_A.setText(QCoreApplication.translate("MyWidget_TestButton", u"Button_A", None))
self.pushButton_B.setText(QCoreApplication.translate("MyWidget_TestButton", u"Button_B", None))
self.label.setText("")
# retranslateUi
if __name__ == "__main__":
app = QApplication(sys.argv)
win = Main()
win.show()
sys.exit(app.exec())

Related

Images Flickering on Pygame [duplicate]

This question already has an answer here:
Why is the PyGame animation is flickering
(1 answer)
Closed 2 years ago.
I am trying to add some buttons to my program and I have managed to put them on there. However, they keep flickering and I'm not sure how to stop that problem. The sizes and positioning are going to be changed later I just used random positions for now so ignore that. I put pygame.display.flip() everywhere hoping that would fix it. However, it did not. Thank you
import pygame
import pygame.freetype
from pygame.sprite import Sprite
from pygame.rect import Rect
PINK = (250, 100, 100)
WHITE = (255, 255, 255)
BLACK = (0,0,0)
#initialize pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
#images
loginBut = pygame.image.load('loginBut.png').convert_alpha()
signupBut = pygame.image.load('signupBut.png').convert_alpha()
pygame.display.flip()
#variables
xbut = 300
ybut1 = 350
ybut2 = 450
def create_surface_with_text(text, font_size, text_rgb, bg_rgb):
font = pygame.freetype.SysFont("Arial", font_size, bold=True)
surface, _ = font.render(text=text, fgcolor=text_rgb, bgcolor=bg_rgb)
return surface.convert_alpha()
def loginButton(xbut,ybut1):
screen.blit(loginBut,(xbut,ybut1))
pygame.display.update()
def signupButton(xbut,ybut2):
screen.blit(signupBut,(xbut,ybut2))
pygame.display.update()
pygame.display.flip()
class UIElement(Sprite):
def __init__(self, center_position, text, font_size, bg_rgb, text_rgb):
self.mouse_over = False
# what happens when the mouse is not over the element
default_image = create_surface_with_text(
text=text, font_size=font_size, text_rgb=text_rgb, bg_rgb=bg_rgb
)
# what happens when the mouse is over the element
highlighted_image = create_surface_with_text(
text=text, font_size=font_size * 1.1, text_rgb=text_rgb, bg_rgb=bg_rgb
)
self.images = [default_image, highlighted_image]
self.rects = [
default_image.get_rect(center=center_position),
highlighted_image.get_rect(center=center_position),
]
super().__init__()
#property
def image(self):
return self.images[1] if self.mouse_over else self.images[0]
#property
def rect(self):
return self.rects[1] if self.mouse_over else self.rects[0]
def update(self, mouse_pos):
if self.rect.collidepoint(mouse_pos):
self.mouse_over = True
else:
self.mouse_over = False
def draw(self, surface):
surface.blit(self.image, self.rect)
pygame.display.flip()
def main():
pygame.init()
screen = pygame.display.set_mode((800, 600))
uielement = UIElement(
center_position=(400, 100),
font_size=40,
bg_rgb=PINK,
text_rgb=BLACK,
text="Welcome to the Automated Timetable Program",
)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
screen.fill(PINK)
uielement.update(pygame.mouse.get_pos())
uielement.draw(screen)
pygame.display.flip()
loginButton(xbut,ybut1)
signupButton(xbut,ybut2)
pygame.display.flip()
if __name__ == "__main__":
main()
The issue is caused by the multiple calles of pygame.display.flip(). Multiple calls to pygame.display.update() or pygame.display.flip() cause flickering. Remove all the calls of pygame.display.flip() from the code, but call it once at the end of the application loop.

Game Of Life - Embedding the pygame window in tkinter to add buttons [duplicate]

This question already has answers here:
Embedding a Pygame window into a Tkinter or WxPython frame
(3 answers)
Closed last year.
So I'm making a game in pygame, and I want to use tkinter as well. I embedded a pygame window into a tkinter window, but I can't seem to do anything with it.
For context, here is the full code:
import Tkinter as tk
import os
import platform
import pygame
class window(object):
def __init__(self):
self.root = tk.Tk() # Main window
self.root.title("SquareScape")
self.root.iconbitmap(r'C:\Users\17_es\PycharmProjects\square_puzzle\images\icon.ico')
self.root.configure(background='#9b9b9b')
# Large Frame
self.win_frame = tk.Frame(self.root, width=670, height=520, highlightbackground='#595959', highlightthickness=2)
# menu (left side)
self.menu = tk.Frame(self.win_frame, width=150, height=516, highlightbackground='#595959', highlightthickness=2)
self.menu_label = tk.Label(self.menu, text="Settings", bg='#8a8a8a', font=("Courier", "16", "bold roman"))
self.mute = tk.Button(self.menu, text="XXXX", font="Courier", bg='#bcbcbc', activebackground='#cdcdcd')
# pygame
self.pygame_frame = tk.Frame(self.win_frame, width=514, height=514, highlightbackground='#595959', highlightthickness=2)
self.embed = tk.Frame(self.pygame_frame, width=512, height=512,)
# Packing
self.win_frame.pack(expand=True)
self.win_frame.pack_propagate(0)
self.menu.pack(side="left")
self.menu.pack_propagate(0)
self.menu_label.pack(ipadx=60, ipady=2)
self.mute.pack(ipadx=40, ipady=2, pady=5)
self.pygame_frame.pack(side="left")
self.embed.pack()
#This embeds the pygame window
os.environ['SDL_WINDOWID'] = str(self.embed.winfo_id())
if platform.system == "Windows":
os.environ['SDL_VIDEODRIVER'] = 'windib'
#Start pygame
pygame.init()
self.win = pygame.display.set_mode((512, 512))
self.win.fill(pygame.Color(255, 255, 255))
pygame.display.init()
self.root.mainloop()
screen = window()
#Here is sample code that I want to run
pygame.draw.rect(screen.win, (0, 0, 255), (200, 200, 100, 100))
When I use pygame.draw.rect(screen.win, (0, 0, 255), (200, 200, 100, 100)), nothing happens. Using pygame inside the class worked, but in my more complicated game, using self.variable for all my variables seems unnecessary.
How can I run my code in the pygame window outside of the window class?
So - besides the obvious missing call to pygame.display.flip - which I suppose is what you intended with the call to pygame.display.init (pygame.init already calls that one) - what I found out is that tkinter needs to initialize its windows and widgets before the packed frame is fully available to be used by Pygame.
I did that by adding a call to self.root.update_idletasks() before calling pygame.init -- that, and explicitly setting the video driver for my platform (which you already does for Windows), made things work.
Anyway, also, in your code you did not show were you wanted to make the calls to Pygamedrawing functions - as it is, it is well possible that everything is correct, but the code after screen.window() is just never run (or rather, just run at program exit) - because you call tkinter.mainloop inside the __init__ method of your application class.
Moving the call to mainloop outside the __init__ is a good practice, so you can initialize other objects and resources as well - and you actualy do have the screen object to operate things on. By making that call inside __init__ is like your whole program was running "inside the initialization".
In short:
call tkinter.update_iddletasks() before initializing pygame
remember to call pygame.display.flip after you draw anything with Pygame
arrange your code so that your drawing calls are actually executed, and not blocked after the call to enter tkinter's loop
You should seriously consider using Python 3.7 or later - (the only "python 2" code there is import Tkinter which becomes import tkinter in Python 3). Python 2 is really at the end of line, and there are no updates for projects like pygame on it.
.
That said, here is your code, modified to run on Linux + Python 3 (should still work on Windows), and to actually perform some actions using the embedded pygame frame.
import tkinter as tk
import os
import platform
import pygame
import time
class window(object):
def __init__(self):
self.root = tk.Tk() # Main window
self.root.title("SquareScape")
# self.root.iconbitmap(r'C:\Users\17_es\PycharmProjects\square_puzzle\images\icon.ico')
self.root.configure(background='#9b9b9b')
# Large Frame
self.win_frame = tk.Frame(self.root, width=670, height=520, highlightbackground='#595959', highlightthickness=2)
# menu (left side)
self.menu = tk.Frame(self.win_frame, width=150, height=516, highlightbackground='#595959', highlightthickness=2)
self.menu_label = tk.Label(self.menu, text="Settings", bg='#8a8a8a', font=("Courier", "16", "bold roman"))
self.mute = tk.Button(self.menu, text="XXXX", font="Courier", bg='#bcbcbc', activebackground='#cdcdcd')
tk.Button(self.menu, text="<->", command=lambda: setattr(self, "direction", (-self.direction[0], self.direction[1]))).pack()
tk.Button(self.menu, text="^", command=lambda: setattr(self, "direction", (self.direction[0], -self.direction[1]))).pack()
# pygame
self.pygame_frame = tk.Frame(self.win_frame, width=514, height=514, highlightbackground='#595959', highlightthickness=2)
self.embed = tk.Frame(self.pygame_frame, width=512, height=512,)
# Packing
self.win_frame.pack(expand=True)
self.win_frame.pack_propagate(0)
self.menu.pack(side="left")
self.menu.pack_propagate(0)
self.menu_label.pack(ipadx=60, ipady=2)
self.mute.pack(ipadx=40, ipady=2, pady=5)
self.pygame_frame.pack(side="left")
self.embed.pack()
#This embeds the pygame window
os.environ['SDL_WINDOWID'] = str(self.embed.winfo_id())
system = platform.system()
if system == "Windows":
os.environ['SDL_VIDEODRIVER'] = 'windib'
elif system == "Linux":
os.environ['SDL_VIDEODRIVER'] = 'x11'
self.root.update_idletasks()
#Start pygame
pygame.init()
self.win = pygame.display.set_mode((512, 512))
self.bg_color = (255, 255, 255)
self.win.fill(self.bg_color)
self.pos = 0, 0
self.direction = 10, 10
self.size = 40
self.color = (0, 255, 0)
self.root.after(30, self.update)
self.root.mainloop()
def update(self):
first_move = True
pygame.draw.rect(self.win, self.bg_color, self.pos + (self.size, self.size))
self.pos = self.pos[0] + self.direction[0], self.pos[1] + self.direction[1]
if self.pos[0] < 0 or self.pos[0] > 512 - self.size:
self.direction = -self.direction[0], self.direction[1]
self.pos = self.pos[0] + 2 * self.direction[0], self.pos[1] + self.direction[1]
if self.pos[1] < 0 or self.pos[1] > 512 - self.size:
self.direction = self.direction[0], -self.direction[1]
self.pos = self.pos[0] + self.direction[0], self.pos[1] + 2 * self.direction[1]
pygame.draw.rect(self.win, self.color, self.pos + (self.size, self.size))
pygame.display.flip()
self.root.after(30, self.update)
screen = window()
tk.mainloop()

Multilpe screen in wxpython

all.
I'd like to be able to switch between multiple screens. Meaning, the first one is the main, then when with a button or an external switch is activated I can see the page #2, in that one I may have an other button to return to the first one, or going to #3, etc. Cause I have a main screen for a big RPM meter, but I may want to see instead all three meter on the same page, or view the raw data in an other page, or go to the set-up page or elsewhere in the future development. I'm using the full screen space for my graphic. Maybe something like "hide" or "show" a page with an event of some kind. I have a single class script for every pages so far, but unable to group them in a single one. Thanks for your help
I wrote about this concept several years ago here. I went ahead an reproduced the example from that article:
import wx
import wx.grid as gridlib
class PanelOne(wx.Panel):
""""""
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent=parent)
txt = wx.TextCtrl(self)
class PanelTwo(wx.Panel):
""""""
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent=parent)
grid = gridlib.Grid(self)
grid.CreateGrid(25,12)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(grid, 0, wx.EXPAND)
self.SetSizer(sizer)
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY,
"Panel Switcher Tutorial")
self.panel_one = PanelOne(self)
self.panel_two = PanelTwo(self)
self.panel_two.Hide()
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.panel_one, 1, wx.EXPAND)
self.sizer.Add(self.panel_two, 1, wx.EXPAND)
self.SetSizer(self.sizer)
menubar = wx.MenuBar()
fileMenu = wx.Menu()
switch_panels_menu_item = fileMenu.Append(wx.ID_ANY,
"Switch Panels",
"Some text")
self.Bind(wx.EVT_MENU, self.onSwitchPanels,
switch_panels_menu_item)
menubar.Append(fileMenu, '&File')
self.SetMenuBar(menubar)
def onSwitchPanels(self, event):
""""""
if self.panel_one.IsShown():
self.SetTitle("Panel Two Showing")
self.panel_one.Hide()
self.panel_two.Show()
else:
self.SetTitle("Panel One Showing")
self.panel_one.Show()
self.panel_two.Hide()
self.Layout()
# Run the program
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()
The basic idea here is to Hide() one panel and Show() another. You might also want to look at the Notebook controls that wxPython provides as they have a similar functionality.

Python Qt Designer Button that creates subsequent text entries

I'm trying to make a GUI in Qt Designer that has one text entry box and a button off to the side that inserts another text entry box below the first. I would potentially need to do this a dozen times or more.
This is my example code from Qt Designer:
from PySide import QtCore, QtGui
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(247, 300)
self.pushButton = QtGui.QPushButton(Dialog)
self.pushButton.setGeometry(QtCore.QRect(110, 10, 75, 23))
self.pushButton.setObjectName("pushButton")
self.lineEdit1 = QtGui.QLineEdit(Dialog)
self.lineEdit1.setGeometry(QtCore.QRect(20, 10, 31, 20))
self.lineEdit1.setObjectName("lineEdit1")
self.lineEdit2 = QtGui.QLineEdit(Dialog)
self.lineEdit2.setGeometry(QtCore.QRect(60, 10, 31, 20))
self.lineEdit2.setObjectName("lineEdit2")
self.retranslateUi(Dialog)
# QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL("clicked()"), Dialog.add_wells) #
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
Dialog.setWindowTitle(QtGui.QApplication.translate("Dialog", "Dialog", None, QtGui.QApplication.UnicodeUTF8))
self.pushButton.setText(QtGui.QApplication.translate("Dialog", "PushButton", None, QtGui.QApplication.UnicodeUTF8))
and this is the code to run the GUI:
from PySide.QtGui import *
from PySide.QtCore import *
import sys
import addentryexample
class MainWindow(QDialog, addentryexample.Ui_Dialog):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.connect(self.pushButton, SIGNAL("clicked()"), self.add_entry)
def add_entry(self):
pass
app = QApplication(sys.argv)
form = MainWindow()
form.show()
app.exec_()
I'm struggling on how to iterate each name of the text box entry so I can pick the values from them later on. I think placing them should just require adding a certain amount to each 'setGeometry' attribute.
Any help would be appreciated!
You can use findChildren:
lineEdits = form.findChildren(QLineEdit)
for lineEdit in lineEdits:
print lineEdit.objectName()

Running Pyqt UIs in tabs using TabWidget

I want to run my app in different tabs. Rightnow, it is running in main window. I have done some search work on how to create tabs. I found this to be useful, but not sufficient to meet my requirements
Create TAB and create textboxes that take data in the TAB-page
I want to have a feature of adding a new tab (like new tab in chrome)
Below is my code sample. I described what i require in the comments.
from PyQt4 import Qt, QtCore, QtGui
import sys
class Map(QtGui.QMainWindow):
def __init__(self,parentQExampleScrollArea=None,parentQWidget = None):
super(Map,self).__init__()
self.initUI()
#Initialize the UI
def initUI(self):
#Initilizing Menus toolbars
#This must be maintained in all tabbed panes
filename = ""
#Filename is obtained through open file button in file menu
self.filename = filename
def paintEvent(self, e):
qp = QtGui.QPainter()
qp.begin(self)
self.drawPoints(qp,self.filename)
qp.end()
def drawPoints(self, qp,FILENAME=""):
#Read contents in file
#Get the necessary coordinates
#A separate class for storing the info of all the coordinates
#Run a for loop for all the coordinates in the list
#Actually, object is created here and image of that object is set
# as a square using the coordinates
qp.setBrush(QtGui.QColor(255, 0, 20, 200))
qp.drawRect(20,20,75,75)
qp.drawRect(100,20,75,75)
self.update()
#There are many functions to handle keyboard and mouse events
def main():
#How do I modify so that I can have multiple tabs
#And show images of the coordinates in files
#Basically I want to have the feature of opening many files
# and displaying them in UI
#Basically a feature to add a new tab
#like that of in eclipse netbeans sublime etc
app = QtGui.QApplication(sys.argv)
myQExampleScrollArea = Map()
myQExampleScrollArea.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Thanks in advance.. :)
It's simply to use method int QTabWidget.addTab (self, QWidget widget, QString) to create widget in tab. In each tab, I suggest use QtGui.QWidget more than QtGui.QMainWindow;
Example;
import sys
from PyQt4 import QtGui
class QCustomWidget (QtGui.QWidget):
# Your widget to implement
# Put your override method here
def paintEvent (self, eventQPaintEvent):
currentQPainter = QtGui.QPainter()
currentQPainter.begin(self)
currentQPainter.setBrush(QtGui.QColor(255, 0, 20, 200))
currentQPainter.drawRect(20, 20, 75, 75)
currentQPainter.drawRect(100, 20, 75, 75)
self.update()
currentQPainter.end()
class QCustomTabWidget (QtGui.QTabWidget):
def __init__ (self, parent = None):
super(QCustomTabWidget, self).__init__(parent)
self.addTab(QtGui.QPushButton('Test'), 'Tab 1')
self.addTab(QCustomWidget(), 'Tab 2')
myQApplication = QtGui.QApplication([])
myQCustomTabWidget = QCustomTabWidget()
myQCustomTabWidget.show()
sys.exit(myQApplication.exec_())
So handle with more tab, It's bad to create many line call int QTabWidget.addTab (self, QWidget widget, QString). Anyway, All widget has add in QTabWidget is can reference in ifself. So, your can control element in it by call QWidget QTabWidget.widget (self, int index).
Example to call widget in tab widget;
import os
import sys
from PyQt4 import QtCore, QtGui
class QCustomLabel (QtGui.QLabel):
def __init__(self, imagePath, parentQWidget = None):
super(QCustomLabel, self).__init__(parentQWidget)
self.setPixmap(QtGui.QPixmap(imagePath))
class QCustomWidget (QtGui.QWidget):
def __init__ (self, parentQWidget = None):
super(QCustomWidget, self).__init__(parentQWidget)
self.addQPustButton = QtGui.QPushButton('Open image')
self.addQPustButton.setMaximumWidth(120)
self.addQPustButton.released.connect(self.openImage)
self.workSpaceQTabWidget = QtGui.QTabWidget()
self.workSpaceQTabWidget.setTabsClosable(True)
self.workSpaceQTabWidget.tabCloseRequested.connect(self.closeImage)
allQVBoxLayout = QtGui.QVBoxLayout()
allQVBoxLayout.addWidget(self.addQPustButton)
allQVBoxLayout.addWidget(self.workSpaceQTabWidget)
self.setLayout(allQVBoxLayout)
def openImage (self):
path = QtGui.QFileDialog.getOpenFileName(self, 'Open image')
if not path.isEmpty():
self.workSpaceQTabWidget.addTab(QCustomLabel(path), QtCore.QString(os.path.basename(str(path))))
def closeImage (self, currentIndex):
currentQWidget = self.workSpaceQTabWidget.widget(currentIndex)
currentQWidget.deleteLater()
self.workSpaceQTabWidget.removeTab(currentIndex)
myQApplication = QtGui.QApplication([])
myQCustomWidget = QCustomWidget()
myQCustomWidget.show()
sys.exit(myQApplication.exec_())

Resources