Button Click Event on IronPython + Wpf - python

Im new to python and VS and im trying to make a simple GUI with a button.
Once I click the button I want it to print(5).
The code looks as following but when I click "run" it exits without any action:
import wpf
from System.Windows import Application, Window
class MyWindow(Window):
def __init__(self):
wpf.LoadComponent(self, 'WpfApplication1.xaml')
BUTTON.Click += self.Button_Click
print(5)
def Button_Click(self, sender, e):
pass
if __name__ == '__main__':
Application().Run(MyWindow())
XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WpfApplication1" Height="300" Width="300">
<Grid>
<Button x:Name="BUTTON" Content="Button" HorizontalAlignment="Left" Margin="101,82,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click" Background="#FFFF1616"/>
</Grid>
</Window>
Thank you.

You have to add an event handler for the button click. Just add this to your window init. (BUTTON should match the button's name on your xaml code)
ui = wpf.LoadComponent(self, 'WpfApplication1.xaml')
ui.BUTTON.Click += self.Button_Click
You can also achieve the same through the xaml code :
 <Button x:Name="BUTTON" Click="Button_Click"></Button>
Working code with comments below:
import wpf
from System.Windows import Application, Window
class MyWindow(Window):
def __init__(self):
self.ui = wpf.LoadComponent(self, 'form.xaml')
# not needed because event handler
# is in XAML
# to handle event on code, remove this from xaml's button tag:
# Click="Button_Click"
# and uncomment line below:
# self.ui.Button.Click += self.Button_Click
def Button_Click(self, sender, e):
print('Button has clicked')
if __name__ == '__main__':
Application().Run(MyWindow())
# Alternatively, below also works:
# form = MyWindow()
# form.ShowDialog()
See screenshot of working form:

Related

QPushButton.clicked.connect doesn't seem to work

I am trying to decouple entirely my GUI from my controller class, and for some reason I can't seem to manage to connect my buttons from outside of my GUI class itself.
Here's a small example of what I mean :
import sys
from PySide6 import QtWidgets
class Gui(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Gui, self).__init__(parent)
layout = QtWidgets.QHBoxLayout(self)
self.button = QtWidgets.QPushButton("Do stuff")
layout.addWidget(self.button)
class Controller(object):
def do_stuff(self):
print("something")
def startup(parent):
ctrl = Controller()
gui = Gui(parent)
gui.button.clicked.connect(ctrl.do_stuff)
return gui
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
dialog = QtWidgets.QDialog()
gui = startup(dialog)
dialog.show()
sys.exit(app.exec_())
I would expect this code, when run, to display a GUI with one push button (which it does), and when pressing the push button, I'd expect the word "something" to get printed. However this doesn't seem to be the case.
I might just be too tired, but I can't find the solution.
What am I missing?
Thanks a lot in advance!
ctrl = None
gui = None
def startup(parent):
global ctrl
global gui
ctrl = Controller()
gui = Gui(parent)
gui.button.clicked.connect(ctrl.do_stuff)
return gui
try this, and it does work. when the variable is in the function, it will be destroyed before the function is finished. the global variable is not a good coding style but is a simple way to figure out your confusion.

PyQt5 SystemTrayIcon's Context Menu doesn't accept key strokes when triggered programmatically

I have a python script that uses PyQt5 to place a system Tray Icon, which I can use to run other scripts.
It's excellent for multiple scripts handling, and since I don't use them often there is no point assigning keyboard shortcuts for all of those scripts.
As long as I use the right-click to open the context menu, it's fine, but I'd also like to trigger it from keystrokes. The problem I faced is when I don't click at the Icon, even if the menu is shown the focus is not there so any other keystrokes don't reach there.
The part to trigger the context menu is:
#QtCore.pyqtSlot(QDBusMessage)
def dmsg(self, message):
menu = self.icon.contextMenu()
if menu.isVisible():
menu.close()
else:
menu.exec(QtCore.QPoint(0,0))
# menu.show()
I can use the dbus to send a signal which triggers this function and the ContextMenu can be seen without having to click the system tray Icon.
I use dbus-send --system / gaurav.menu.toggle to send the signal to toggle the context menu visibility, and it works.
A reproducible example is as follows:
from PyQt5 import QtGui, QtWidgets, QtCore
from PyQt5.QtDBus import QDBusConnection, QDBusMessage
import sys
def exe_script(name):
action = name.text()
if action == '&Exit':
sys.exit(0)
elif action == '&Hello':
print('hello')
def read_actions():
return
def get_menu(all_actions):
menu = QtWidgets.QMenu()
actions = []
for name in ['&Exit', '&Hello']:
mi = menu.addAction(name)
actions.append(mi)
menu.triggered.connect(lambda q:exe_script(q))
return menu,actions
class QDBhandler(QtCore.QObject):
def __init__(self,icon):
super(QDBhandler,self).__init__()
bus = QDBusConnection.systemBus()
bus.registerObject('/', self)
bus.connect(
'',
'/',
'gaurav.menu',
'toggle',
self.dmsg
)
self.icon = icon
#QtCore.pyqtSlot(QDBusMessage)
def dmsg(self, message):
menu = self.icon.contextMenu()
if menu.isVisible():
menu.close()
else:
menu.exec(QtCore.QPoint(0,0))
# menu.show()
def main():
app = QtWidgets.QApplication(sys.argv)
icon = QtWidgets.QSystemTrayIcon()
handler = QDBhandler(icon)
icon.setToolTip('Execute Scripts')
actions_dict = read_actions()
menu,actions = get_menu(actions_dict)
icon.setContextMenu(menu)
icon.show()
sys.exit(app.exec())
if __name__ == '__main__':
main()
System Information:
Archlinux, i3-gaps window manager

python pyqt5 mouseEvent and mouseLocation

I'm trying to make videogame macro with pyautogui and pyqt5
this is what I want
Press the button and hold it. (mouse pressed)
Drag somewhere outside the GUI window.
release it. (mouse released)
Get the mouse location when the mouse is released
but I couldn't find a way to connect mouse event with button clicks.
class MyWindow(QDialog, form_class):
def __init__(self):
super().__init__()
self.mouseLocation = {}
self.setupUi(self)
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
self.menuBtn.clicked.connect( lambda: self.addLocation('MenuBtn')) # ButtonEvents
self.traininBtn.pressed.connect( lambda: self.addLocation('TraininBtn'))
self.difficultyBtn.pressed.connect( lambda: self.addLocation('DifficultyBtn'))
self.lonewolfBtn.pressed.connect( lambda: self.addLocation('LonewolfBtn'))
def addLocation(self, name):
self.mouseLocation[name] = [pyautogui.position().x, pyautogui.position().y]
def mouseReleaseEvent(self, e):
print('BUTTON RELEASED')
if __name__ == "__main__":
app = QApplication(sys.argv)
myWindow = MyWindow()
myWindow.show()
app.exec_()

How to restore focus on a widget after hidding then showing the parent widget?

I'm creating a launcher application (like Spotlight/Albert/Gnome-Do). I'm using Python 2.7 and Pyside. Made and used on Windows 10.
It is running in the background and listening to a shortcut with the keyboard (pip install keyboard). When the shortcut is called, a QObject signal calls the show method of my main widget.
My issue is that when the main widget gets hidden by pressing escape or return, next time the widget is shown, the focus will be in the QlineEdit and the user will be able to type its query straight away.
But when the widget is hidden by clicking outside widget (handled by filtering the QEvent WindowDeactivate), the focus won't be on my QLineEdit at next call, which ruins the user experience.
I've tried playing with activateWindow() or raise_(), but it doesn't change anything.
Heree here a simplified example code that shows my problem:
import sys
import keyboard
from PySide.QtCore import *
from PySide.QtGui import *
SHORTCUT = 'Ctrl+space'
class ShortcutThread(QObject):
signal = Signal()
class Launcher(QMainWindow):
def __init__(self, parent=None):
super(Launcher, self).__init__()
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.Popup)
self.resize(500, 50)
self.central_widget = QWidget()
self.setCentralWidget(self.central_widget)
self.layout_ = QHBoxLayout()
self.central_widget.setLayout(self.layout_)
self.search = QLineEdit()
self.layout_.addWidget(self.search)
def eventFilter(self, obj, event):
# Hide dialog when losing focus
if event.type() == QEvent.WindowDeactivate:
self.hide()
return super(Launcher, self).eventFilter(obj, event)
def keyPressEvent(self, e):
# Hide dialog when pressing escape or return
if e.key() in [Qt.Key_Escape, Qt.Key_Return]:
self.hide()
def main():
app = QApplication(sys.argv)
app.setQuitOnLastWindowClosed(False)
launcher = Launcher()
shortcut = ShortcutThread()
shortcut.signal.connect(launcher.show)
keyboard.add_hotkey(SHORTCUT, shortcut.signal.emit, args=[])
launcher.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
When I call the shortcut (Ctrl+Space here) and click elsewhere, next time I'll call the shortcut, the focus won't be set to the QLineEdit widget.
When the launcher is hidden by hitting return or escape, it does work as expected.

PyQt5 Interrupt Close Event from Outside the Main Gui Module

I use Qt Designer to build my GUI's and convert them to py files using pyuic5. My end goal here is to interrupt the user from closing the program when a variable == 1 and present them with an 'are you sure you want to close?' type dialog. If said variable == 0 then just close the program normally.
I have seen lots of examples on how to do this, but all of them require editing the code in the GUI module. I import my gui.py file created by pyuic5 into my main script where I do all my connections to buttons, line edits, etc.. I do this so that at anytime I can update the GUI with Qt Designer and not affect the programs functionality.
Is there a way to do this from my main script that has the GUI module from Qt Designer imported?
Example of how my main script is structured:
import philipsControlGui
import sys
def main():
MainWindow.show()
sys.exit(app.exec_())
def test():
print('test')
# Main window setup
app = philipsControlGui.QtWidgets.QApplication(sys.argv)
MainWindow = philipsControlGui.QtWidgets.QMainWindow()
ui = philipsControlGui.Ui_MainWindow()
ui.setupUi(MainWindow)
# Main window bindings
ui.onButton.clicked.connect(test)
### Can I insert something here to do: if user closes the window... do something else instead?
if __name__ == "__main__":
main()
You should create a subclass from your imported gui so you can reimplement the closeEvent method:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from philipsControlGui import Ui_MainWindow
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setUpUi(self)
self.ui.onButton.clicked.connect(self.test)
self._check_close = True
def test(self):
print('test')
self._check_close = not self._check_close
def closeEvent(self, event):
if self._check_close:
result = QtWidgets.QMessageBox.question(
self, 'Confirm Close', 'Are you sure you want to close?',
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
if result == QtWidgets.QMessageBox.Yes:
event.accept()
else:
event.ignore()
def main():
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
If there's a specific 'ExitButton' in your design, you should be able to connect it in the main code and create a pop up dialog. You would have to import the QtCore/QtGui components. I always write my GUI directly (QtDesigner is pain when it comes to these things) so I'm assuming something like this:
from PyQt4.QtGui import *
from PyQt4.QtCore import *
[YOUR CODE]
ui.ExitButton.clicked.connect(Exit)
def Exit():
msg = QMessageBox()
msg.setIcon(QMessageBox.Information)
msg.setText("Are you sure you want to close this window?")
msg.setWindowTitle("MessageBox demo")
msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
msg.buttonClicked.connect(msgbtn)
retval = msg.exec_()
print "value of pressed message box button:", retval

Categories

Resources