PyQt 5 - Pop Up Window Flashes before Closing - python

I am trying to create a pop up window upon the click of a Qpushbutton.
Upon pressing the pushbutton, a window flashes on my screen, but disappears quickly thereafter. I have tried playing with adding a sys.exit(app.exec_()) statement in the function (proceed_new_table in code snip below) that creates the pop up screen, but the results are not as I desire.
Any ideas on how to make this pop-up screen stay permanently?
Code below:
import sys
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QAction, QTableWidget,QTableWidgetItem,QVBoxLayout,QPushButton, QLabel
from PyQt5.QtCore import Qt, pyqtSlot, QSize
# this routine creates the table widget, it only appears due to being called below
class TableView(QTableWidget):
def __init__(self, z, vert, *args):
QTableWidget.__init__(self, *args)
self.z = z
self.setz()
self.setMinimumSize(QSize(800, 400)) # Set sizes
self.setWindowTitle('General Spandrel Information Form') # Set the window title
# self.resizeColumnsToContents()
# self.resizeRowsToContents()
self.setVerticalHeaderLabels(vert)
def setz(self):
horHeaders = []
for n, key in enumerate(sorted(self.z.keys())):
horHeaders.append(key)
for m, item in enumerate(self.z[key]):
newitem = QTableWidgetItem(item)
self.setItem(m, n, newitem)
self.setHorizontalHeaderLabels(horHeaders)
#pulls the create new table function
def proceed_new_table(self):
exPopup = ExampleTable_button_push()
#exPopup.setGeometry(600, 400, 400, 400)
exPopup.show()
#sys.exit(app.exec_())
# this routine creates the button widget, it only appears due to being called below
class Buttons(QPushButton):
def __init__(self, *args):
QPushButton.__init__(self, *args)
okButton = QPushButton("OK",self)
okButton.setToolTip('Press after inputting all values in table')
#this is the on_event trigger
okButton.clicked.connect(self.on_click)
#the on_click function pulls the classs of
def on_click(self):
TableView.proceed_new_table(self)
#this is what happens if the button is pushed
class ExampleTable_button_push(QPushButton):
def __init__(self,*args):
QPushButton.__init__(self, *args)
okButton = QPushButton("OK",self)
okButton.setToolTip('Press after inputting all values in table')
#this is the main window function
def main(args):
app = QApplication(args)
table = TableView(z, vert, 4, 4)
button = Buttons()
table.setCellWidget(3,0,button)
table.show()
sys.exit(app.exec_())
z={'a':[2,2,2],'b':[3,3,3],'c':[4,4,4]}
vert = ["Line 1","Line 2", "Line 3"]
if __name__ == '__main__':
#main(sys.argv)
app = QApplication(sys.argv)
ex = main(sys.argv)
#sys.exit(app.exec_())

I don’t understand what you want to do, but try the example below.
I noted the lines in which I made changes.
import sys
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QAction, QTableWidget,QTableWidgetItem,QVBoxLayout,QPushButton, QLabel
from PyQt5.QtCore import Qt, pyqtSlot, QSize
# this routine creates the table widget, it only appears due to being called below
class TableView(QTableWidget):
def __init__(self, z, vert, *args):
QTableWidget.__init__(self, *args)
self.z = z
self.setz()
self.setMinimumSize(QSize(800, 400))
self.setWindowTitle('General Spandrel Information Form')
self.setVerticalHeaderLabels(vert)
button = Buttons(self) # +++
self.setCellWidget(3, 0, button) # +++
def setz(self):
horHeaders = []
for n, key in enumerate(sorted(self.z.keys())):
horHeaders.append(key)
for m, item in enumerate(self.z[key]):
newitem = QTableWidgetItem(item)
self.setItem(m, n, newitem)
self.setHorizontalHeaderLabels(horHeaders)
#pulls the create new table function
def proceed_new_table(self):
self.exPopup = ExampleTable_button_push() # + self
#exPopup.setGeometry(600, 400, 400, 400)
self.exPopup.show() # + self
# this routine creates the button widget, it only appears due to being called below
class Buttons(QPushButton):
def __init__(self, *args):
QPushButton.__init__(self, *args)
self.parent = args[0] # +++
okButton = QPushButton("OK", self)
okButton.setToolTip('Press after inputting all values in table')
#this is the on_event trigger
okButton.clicked.connect(self.on_click)
#the on_click function pulls the classs of
def on_click(self):
# TableView.proceed_new_table(self)
self.parent.proceed_new_table() # +++
#this is what happens if the button is pushed
class ExampleTable_button_push(QPushButton):
def __init__(self,*args):
QPushButton.__init__(self, *args)
okButton = QPushButton("OK",self)
okButton.setToolTip('Press after inputting all values in table')
z = {'a':[2,2,2],'b':[3,3,3],'c':[4,4,4]}
vert = ["Line 1","Line 2", "Line 3"]
#this is the main window function
#def main(args):
if __name__ == '__main__':
app = QApplication(sys.argv)
table = TableView(z, vert, 4, 4)
# button = Buttons()
# table.setCellWidget(3, 0, button)
table.show()
sys.exit(app.exec_())

okButton has no reference outside of Buttons.__init__ so the garbage collecting is destroying it.
You could try to keep a ref, for example as self.okButton

Related

I want to change the sound that plays every time a button is pressed depending on a checked actiion in a QMenu

I have a QMainWindow, inside there is a QMenu, QLineEdit, and one QPushButton.
Every time I click the button, it plays a sound and then adds a text to the QLineEdit.
In my QMenu the user must be able to choose which sound plays by checking it.
I tried to achieve this by changing a variable self.s inside the MainWindow class every time a QAction is checked, meanwhile, the other QAction's are unchecked. So in my playsound() I just put the self.view.s as the argument.
But it seems that it's only reading the original self.view.s, which is the first sound. My signals to change self.view.s does not work. Also, the other QActions aren't unchecked as I wanted them to.
Below is my code:
import sys
from functools import partial
from playsound import playsound
from threading import Thread
from PyQt6.QtCore import *
from PyQt6.QtGui import *
from PyQt6.QtWidgets import *
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.buttons = {}
self.setWindowTitle("Try")
central_widget = QWidget()
self.setCentralWidget(central_widget)
self.lay = QVBoxLayout(central_widget)
self.lineedit()
button = {"HEY! ": (0, 0, 0, 0)}
page = QWidget()
layout = QGridLayout(page)
for btnText, pos in button.items():
self.buttons[btnText] = QPushButton(btnText)
layout.addWidget(self.buttons[btnText], *pos)
self.lay.addWidget(page)
self.music()
def music(self):
self.s = 'sound1.mp3'
self.x = 'sound1.mp3'
self.y = 'sound2.mp3'
self.z = 'disable.mp3'
def lineedit(self):
self.le = QLineEdit()
self.le.setFixedHeight(35)
self.lay.addWidget(self.le)
def set_lineedit(self, text):
self.le.setText(text)
self.le.setFocus()
def line(self):
return self.le.text()
class Menu:
def __init__(self, MainWindow):
super().__init__()
self.view = MainWindow
self.menuBar()
#self.actionSignals()
def menuBar(self):
self.menuBar = QMenuBar()
self.view.setMenuBar(self.menuBar)
self.menu = QMenu(self.menuBar)
self.menu.setTitle('Menu')
self.sounds = QMenu(self.menu)
self.sounds.setTitle('Select Sound')
self.sound1 = QAction(self.menuBar)
self.sound2 = QAction(self.menuBar)
self.disable = QAction(self.menuBar)
self.mute = QAction(self.menuBar)
self.mute.setText('Mute Background')
self.mute.setCheckable(True)
self.mute.setChecked(False)
self.sound1.setText('Sound 1')
self.sound1.setCheckable(True)
self.sound1.setChecked(True)
self.sound2.setText('Sound 2')
self.sound2.setCheckable(True)
self.sound2.setChecked(False)
self.disable.setText('Disable Sound')
self.disable.setCheckable(True)
self.disable.setChecked(False)
self.sounds.addAction(self.sound1)
self.sounds.addAction(self.sound2)
self.sounds.addAction(self.disable)
self.menuBar.addAction(self.menu.menuAction())
self.menu.addAction(self.mute)
self.menu.addAction(self.sounds.menuAction())
def menu_signals(self):
self.sound1.triggered.connect(self.sound_1)
self.sound2.triggered.connect(self.sound_2)
self.disable.triggered.connect(self.disabled)
def sound_1(self, checked):
if checked:
self.sound2.setChecked(False)
self.disable.setChecked(False)
self.view.s = self.view.x
else:
self.sound1.setChecked(True)
def sound_2(self, checked):
if checked:
self.sound1.setChecked(False)
self.disable.setChecked(False)
self.view.s = self.view.y
else:
self.sound2.setChecked(True)
def disabled(self, checked):
if checked:
self.sound2.setChecked(False)
self.sound1.setChecked(False)
self.view.s = self.view.z
else:
self.sound1.setChecked(True)
class Controller:
def __init__(self, MainWindow):
self.view = MainWindow
self.connectSignals()
def background(self):
while True:
playsound('background.mp3')
def playsound(self):
playsound(self.view.s, False)
def buildExpression(self, sub_exp):
expression = self.view.line() + sub_exp
self.view.set_lineedit(expression)
def connectSignals(self):
for btnText, btn in self.view.buttons.items():
self.view.buttons[btnText].clicked.connect(self.playsound)
self.view.buttons[btnText].clicked.connect(partial(self.buildExpression, btnText))
app = QApplication(sys.argv)
w = MainWindow()
x = Controller(w)
Thread(target = x.background, daemon = True).start()
m = Menu(w)
w.show()
app.exec()
I want to be able to change the value within playsound() depending on which QAction is checked in the Menu Bar. While one QAction is checked, the other QAction's should be unchecked.
This is where an action group comes into play. QActionGroup allows for mutually exclusive actions. It also provides convenient access to the selected action through the checkedAction method.
Create a QActionGroup object (e.g. self.soundGroup = QActionGroup(self))
Create your actions with the group as parent (e.g. self.sound1 = QAction(self.soundGroup))
For each of your actions, set their corresponding sound as their data, e.g. self.sound1.setData('sound1.mp3')
Ensure the action group is exclusive (I believe it's the default, but you may use self.soundGroup.setExclusive(True))
Use self.soundGroup.checkedAction() to get the checked action (selected sound) instead of self.view.s: playsound(self.soundGroup.checkedAction().data(), False)
You do not need any of your wiring between the actions and updates to self.view.s anymore. Just remove all of that.

Recursion Error on PyQt QStackedWidget when using enterEvent and leaveEvent

I am using a QStackedWidget which has its own enterEvent and leaveEvent. When I move my mouse to the QStackedWidget the enterEvent sets the current index to 1 and on the leaveEvent it sets the current index to 0 so that a different widget is shown on mouse enter and mouse leave in the area of QStackedWidget. It does what I want only if I quickly move my mouse in and out, if I place my mouse too long in the area I get RecursionError: maximum recursion depth exceeded.
Is this because the widgets are changing so fast that the internal stack can't keep up? My question is "How can I make sure this error doesn't occur? I want to display one widget as long as the mouse is over the QStackedWidget and when it is not I want to display the original widget."
The following is the code that I modified (Original Source used buttons to set the index and it is PyQt4)
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QTimeLine
from PyQt5.QtGui import *
class FaderWidget(QWidget):
def __init__(self, old_widget, new_widget):
QWidget.__init__(self, new_widget)
self.old_pixmap = QPixmap(new_widget.size())
old_widget.render(self.old_pixmap)
self.pixmap_opacity = 1.0
self.timeline = QTimeLine()
self.timeline.valueChanged.connect(self.animate)
self.timeline.finished.connect(self.close)
self.timeline.setDuration(333)
self.timeline.start()
self.resize(new_widget.size())
self.show()
def animate(self, value):
self.pixmap_opacity = 1.0 - value
self.repaint()
class StackedWidget(QStackedWidget):
def __init__(self, parent = None):
QStackedWidget.__init__(self, parent)
def setCurrentIndex(self, index):
self.fader_widget = FaderWidget(self.currentWidget(), self.widget(index))
super().setCurrentIndex(index)
def enterEvent(self,event):
self.setCurrentIndex(1)
def leaveEvent(self,event):
self.setCurrentIndex(0)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = QWidget()
stack = StackedWidget()
cal=QCalendarWidget()
stack.addWidget(cal)
editor = QTextEdit()
editor.setPlainText("Hello world! "*100)
stack.addWidget(editor)
layout = QGridLayout(window)
layout.addWidget(stack, 0, 0, 1, 2)
window.show()
sys.exit(app.exec_())
The recursion occurs because when you start the FaderWidget it changes focus and enterEvent is called again which creates a new FaderWidget.
The solution is to verify that the old index is different from the new index to just create the FadeWidget:
import sys
from PyQt5.QtCore import QTimeLine
from PyQt5.QtGui import QPainter, QPixmap
from PyQt5.QtWidgets import (
QApplication,
QCalendarWidget,
QGridLayout,
QStackedWidget,
QTextEdit,
QWidget,
)
class FaderWidget(QWidget):
def __init__(self, old_widget, new_widget):
QWidget.__init__(self, new_widget)
self.pixmap_opacity = 1.0
self.old_pixmap = QPixmap(new_widget.size())
old_widget.render(self.old_pixmap)
self.timeline = QTimeLine()
self.timeline.valueChanged.connect(self.animate)
self.timeline.finished.connect(self.close)
self.timeline.setDuration(333)
self.timeline.start()
self.resize(new_widget.size())
self.show()
def paintEvent(self, event):
painter = QPainter(self)
painter.setOpacity(self.pixmap_opacity)
painter.drawPixmap(0, 0, self.old_pixmap)
def animate(self, value):
self.pixmap_opacity = 1.0 - value
self.update()
class StackedWidget(QStackedWidget):
def setCurrentIndex(self, index):
if self.currentIndex() != index:
self.fader_widget = FaderWidget(self.currentWidget(), self.widget(index))
super().setCurrentIndex(index)
def enterEvent(self, event):
self.setCurrentIndex(1)
def leaveEvent(self, event):
self.setCurrentIndex(0)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = QWidget()
stack = StackedWidget()
cal = QCalendarWidget()
stack.addWidget(cal)
editor = QTextEdit()
editor.setPlainText("Hello world! " * 100)
stack.addWidget(editor)
layout = QGridLayout(window)
layout.addWidget(stack, 0, 0, 1, 2)
window.show()
sys.exit(app.exec_())

How to get data from dynamically created textboxes when a button is clicked in Pyqt5?

I am trying to make a window application in pyqt5 in which user enters a number then click("press me") button .
After that a number of rows are created according to the number entered by the user and one push button ("GO")
Each column has three labels with three textboxes
I managed to make the rows already , but what i can't manage is fetching the data from the textboxes when the push button is clicked
Note1: For simplicity , i was just trying the code for one textbox only then i will add more textboxes
Note2: i heard about some function called Lambda , but i searched for it and i couldn't find good explanation to it
Note3: Similar questions that didn't work for me:
Acessing dynamically added widgets I didn't know how to use this answer as i have two kinds of widgets in the layout , label and qlinedit
getting values from dynamically created qlinedits This answer didn't suit my case as i want one only button to get the data in all created textboxes
Code :
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5 import *
from PyQt5.QtWidgets import QLineEdit,QLabel,QGridLayout
import sys
class Window(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.home()
def home(self):
self.grid=QGridLayout()
self.setLayout(self.grid)
self.label=QLabel(self)
self.label.setText("NO")
self.grid.addWidget(self.label,0,1)
self.pushButton_ok = QtWidgets.QPushButton("Press me", self)
self.pushButton_ok.clicked.connect(self.addtextbox)
self.grid.addWidget(self.pushButton_ok,0,10)
self.input1=QLineEdit(self)
self.grid.addWidget(self.input1,0,5)
def addtextbox(self):
no_of_process=(self.input1.text())
no=int(no_of_process)
n=0
while(n<no):
self.bursttime=QLabel(self)
self.bursttime.setText("b")
self.timeinput=QLineEdit(self)
self.grid.addWidget(self.bursttime,2*n+1,0)
self.grid.addWidget(self.timeinput,2*n+1,1)
n=n+1
self.go=QtWidgets.QPushButton("GO",self)
self.grid.addWidget(self.go,6,0)
self.go.clicked.connect(self.printvalues)
def printvalues():
n=0
#fetch data in some way
application = QtWidgets.QApplication(sys.argv)
window = Window()
window.setWindowTitle('Dynamically adding textboxes using a push button')
window.resize(250, 180)
window.show()
sys.exit(application.exec_())
Main Window of program
when user enters for example 2 to create 2 rows
Try it:
import sys
from PyQt5.QtWidgets import (QLineEdit, QLabel, QGridLayout, QWidget,
QPushButton, QApplication, QSpinBox)
class Window(QWidget):
def __init__(self):
super().__init__()
self.home()
def home(self):
self.grid = QGridLayout()
self.setLayout(self.grid)
self.label = QLabel(self)
self.label.setText("NO")
self.grid.addWidget(self.label, 0, 1)
# self.input1 = QLineEdit(self)
self.input1 = QSpinBox(self) # +++
self.input1.setMinimum(1)
self.input1.setMaximum(12)
self.input1.setValue(3)
self.grid.addWidget(self.input1, 0, 5)
self.pushButton_ok = QPushButton("Press me", self)
self.pushButton_ok.clicked.connect(self.addtextbox) #(self.addCheckbox)
self.grid.addWidget(self.pushButton_ok, 0, 10)
def addtextbox(self):
countLayout = self.layout().count()
if countLayout > 3:
for it in range(countLayout - 3):
w = self.layout().itemAt(3).widget()
self.layout().removeWidget(w)
w.hide()
self.lineEdits = [] # +++
for n in range(self.input1.value()):
self.bursttime = QLabel(self)
self.bursttime.setText("b_{}".format(n))
self.timeinput = QLineEdit(self)
self.timeinput.textChanged.connect(lambda text, i=n : self.editChanged(text, i)) # +++
self.grid.addWidget(self.bursttime, 2*n+1, 0)
self.grid.addWidget(self.timeinput, 2*n+1, 1)
self.lineEdits.append('') # +++
self.go = QPushButton("GO") #, self)
self.grid.addWidget(self.go, 2*n+2, 0)
self.go.clicked.connect(self.printvalues)
def printvalues(self):
# fetch data in some way
for i, v in enumerate(self.lineEdits): # +++
print("bursttime: b_{}, timeinput: {}".format(i, v)) # +++
def editChanged(self, text, i): # +++
self.lineEdits[i] = text # +++
def addCheckbox(self):
print("def addCheckbox(self):")
if __name__ == "__main__":
application = QApplication(sys.argv)
window = Window()
window.setWindowTitle('Dynamically adding textboxes using a push button')
window.resize(250, 180)
window.show()
sys.exit(application.exec_())
I was working on a PyQt5 app which had a dynamically loaded whole tab, with QTableView, QLineEdit and few QPushButtons, and had similar problem, I needed data from that one QLineEdit every tab. I've used QSignalMapper because I had to take data on textChanged() signal, but since you have a simple push button to just grab data, you can use QObject.findChildren() like I did in this example:
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5 import *
from PyQt5.QtWidgets import QLineEdit,QLabel,QGridLayout
import sys
class Window(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.home()
def home(self):
self.grid=QGridLayout()
self.setLayout(self.grid)
self.label=QLabel(self)
self.label.setText("NO")
self.grid.addWidget(self.label,0,1)
self.pushButton_ok = QtWidgets.QPushButton("Press me", self)
self.pushButton_ok.clicked.connect(self.addtextbox)
self.grid.addWidget(self.pushButton_ok,0,10)
self.input1=QLineEdit(self)
self.grid.addWidget(self.input1,0,5)
def addtextbox(self):
no_of_process=(self.input1.text())
no=int(no_of_process)
n=0
while(n<no):
self.bursttime=QLabel(self)
self.bursttime.setText("b")
self.timeinput=QLineEdit(self)
self.timeinput.setObjectName("timeinput_{0}".format(n))
self.grid.addWidget(self.bursttime,2*n+1,0)
self.grid.addWidget(self.timeinput,2*n+1,1)
n=n+1
self.go=QtWidgets.QPushButton("GO",self)
self.grid.addWidget(self.go,6,0)
self.go.clicked.connect(self.printvalues)
def printvalues(self):
for child in self.findChildren(QLineEdit, QtCore.QRegExp("timeinput_(\d)+")):
print(child.text())
application = QtWidgets.QApplication(sys.argv)
window = Window()
window.setWindowTitle('Dynamically adding textboxes using a push button')
window.resize(250, 180)
window.show()
sys.exit(application.exec_())
P.S. I fixed your pushButton_ok.clicked() signal, it was calling addCheckBox() which doesn't exist.

Update PyQt menu

I am trying to dynamically update a menu with new items when I add new items via the form into Qsettings. For example, if you open my code and click the button and then click "new" it will open a QLineEdit with a button. When the button is clicked the list data gets stored via Qsettings.
I'd like to be able to update the menu somehow to show the items without restarting. I tried some things like calling repaint and update in a few areas with no luck.
Here is my code, I slimmed it down the best that I could for the example.
import functools
import sys
from PyQt5 import QtCore
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QWidget, QPushButton, QHBoxLayout, \
QVBoxLayout, QLineEdit,QApplication, QWidgetAction, QTextBrowser, QAction, QMenu
class MainWindow(QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.layout = QHBoxLayout()
self.menu_action = QAction(QIcon("icon.png"),"New", self)
self.menu_btn = QPushButton()
self.menu = MyMenu("Menu", self.menu_btn)
self.add_menu = self.menu.addMenu(QIcon("icon.png"), "Menu")
self.add_menu.addAction(self.menu_action)
self.menu_btn.setMenu(self.menu)
self.textBox = QTextBrowser(self)
action = QWidgetAction(self.menu_btn)
action.setDefaultWidget(self.textBox)
self.menu_btn.menu().addAction(action)
settings = QtCore.QSettings('test_org', 'my_app')
self.new_items = settings.value('new_item', [])
print('%s' % self.new_items)
for item in self.new_items:
self.create_action = QAction(QIcon("icon.png"), item[0], self)
self.create_action.setData(item)
self.add_menu.addAction(self.create_action)
self.create_action.triggered.connect(functools.partial(self.menu_clicked, self.create_action))
self.layout.addWidget(self.menu_btn)
self.setLayout(self.layout)
self.menu_action.triggered.connect(self.open_window)
def open_window(self):
self.create_menu_item = Create_Menu_Item()
self.create_menu_item.show()
def menu_clicked(self, item):
itmData = item.data()
print(itmData)
class Create_Menu_Item(QWidget):
def __init__(self, parent=None):
super(Create_Menu_Item, self).__init__(parent)
self.resize(200, 195)
self.layout = QVBoxLayout()
self.form = QLineEdit()
self.btn = QPushButton()
self.layout.addWidget(self.form)
self.layout.addWidget(self.btn)
self.btn.clicked.connect(self.save_new_item)
self.setLayout(self.layout)
def save_new_item(self):
settings = QtCore.QSettings('test_org', 'my_app')
self.new_item = settings.value('new_item', [])
self.new_item.append([self.form.text()])
settings.setValue('new_item', self.new_item)
print(self.new_item)
print('saved!')
class MyMenu(QMenu):
def event(self,event):
if event.type() == QtCore.QEvent.Show:
self.move(self.parent().mapToGlobal(QtCore.QPoint(0,0))-QtCore.QPoint(0,self.height()))
return super(MyMenu,self).event(event)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec_()
Anyone have any ideas? Thanks.
You can create a for loop to access the list.
Bare in mind it is a list of lists so a nested for loop is neccessary
def save_new_item(self):
settings = QtCore.QSettings('test_org', 'my_app')
self.new_item = settings.value('new_item', [])
self.new_item.append([self.form.text()])
settings.setValue('new_item', self.new_item)
print(self.new_item)
print('saved!')
# Add new menu items..
for x in self.new_item:
for y in x:
print(y)
The above will keep adding the WHOLE list of items every time you add a new item..
To just add the newest item, this is all you need (the last item added to the list)
w.add_menu.addAction(self.new_item[0][-1])
so
def save_new_item(self):
settings = QtCore.QSettings('test_org', 'my_app')
self.new_item = settings.value('new_item', [])
self.new_item.append([self.form.text()])
settings.setValue('new_item', self.new_item)
print(self.new_item)
print('saved!')
#ADD last item in the list
w.add_menu.addAction(self.new_item[0][-1])

PyQt5 (Python): Get value from qpushbutton by contextmenu

I created a few qpushbuttons in a for loop. What I want to do is to access their values (the number which the for loop iterates) by a context menu.
I can create the buttons and with left click, I get their values printed. But when I open a context menu on right click, the triggered command self.value.triggered.connect(partial(self.get_value, number)) only returns the highest value.
What do I have to change in order to get the value by the get_value entry from the context menu?
import sys
from functools import partial
from PyQt5.QtWidgets import QMainWindow, QPushButton, QApplication, QAction, QMenu
from PyQt5.QtCore import Qt
class Main(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.buttons = []
self.value = []
self.context_menu = []
pos_value = [30, 50]
for number in range(0,4):
button_text = "Button " + str(number)
self.buttons.append(QPushButton(button_text, self))
self.buttons[number].move(*pos_value)
self.buttons[number].clicked.connect(self.buttonClicked)
pos_value[0] += 120
self.buttons[number].setContextMenuPolicy(Qt.CustomContextMenu)
self.buttons[number].customContextMenuRequested.connect(partial(self.open_context_menu, number))
self.context_menu.append(QMenu(self))
self.value.append(QAction('Get value ' + str(number), self))
self.context_menu[-1].addAction(self.value[-1])
self.value[-1].triggered.connect(partial(self.get_value, number))
self.setGeometry(300, 300, 600, 150)
self.show()
def buttonClicked(self):
sender = self.sender()
print(sender.text() + ' was pressed')
def get_value(self, value):
print('Value ' + str(value))
def open_context_menu(self, i, point):
self.context_menu[-1].exec_(self.buttons[i].mapToGlobal(point))
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Main()
sys.exit(app.exec_())
EDIT: I found an error in my program, because I have overwritten the variables self.value and self.context_menu. Now this has been fixed, but the error remains.
Any ideas how to fix this?
def open_context_menu(self, i, point):
self.context_menu[-1].exec_(self.buttons[i].mapToGlobal(point))
# ^
# Your bug here

Categories