I wrote global shortcut example for hide and show my windows with key like 'F12', I used python-xlib and some script named 'pyxhook' everything works fine except when i want to hide() and show() window few times my proccess turning a zombie, but same code working with hiding and showing just button.
#!/usr/bin/python
# -*- coding: utf-8; -*-
from gi.repository import Gtk, GObject
from pyxhook import HookManager
GObject.threads_init()
class Win(Gtk.Window):
def __init__(self):
super(Win, self).__init__()
self.connect('destroy', Gtk.main_quit)
self.button = Gtk.Button()
self.add(self.button)
self.resize(200,150)
self.show_all()
def handle_global_keypress(self, event):
if event.Key == 'F12':
if self.get_visible():
self.hide()
else:
self.show()
### this part works fine with button
#if self.button.get_visible():
# self.button.hide()
#else:
# self.button.show()
def main():
app = Win()
hm = HookManager()
hm.HookKeyboard()
hm.KeyDown = app.handle_global_keypress
hm.start()
Gtk.main()
hm.cancel()
if __name__ == "__main__":
main()
edit: i solved my problem using Keybinder library instead of coding pure python keybinder.
http://kaizer.se/wiki/keybinder/
I'm unable to answer your specific question but I might suggest another option. Guake console implements this very same behavior but using dbus:
http://guake.org/
In the dbusiface.py file you can find:
import dbus
import dbus.service
import dbus.glib
import gtk
import guake.common
dbus.glib.threads_init()
DBUS_PATH = '/org/guake/RemoteControl'
DBUS_NAME = 'org.guake.RemoteControl'
class DbusManager(dbus.service.Object):
def __init__(self, guakeinstance):
self.guake = guakeinstance
self.bus = dbus.SessionBus()
bus_name = dbus.service.BusName(DBUS_NAME, bus=self.bus)
super(DbusManager, self).__init__(bus_name, DBUS_PATH)
#dbus.service.method(DBUS_NAME)
def show_hide(self):
self.guake.show_hide()
Among others methods. This is worth to explore. Please also note that Guake is developed using PyGtk and not PyGObject, but anyway you can get some ideas.
Related
I was trying to toy around with the pygtk module to make an app indicator in my top bar in Ubuntu 17.10.
With a little research, I have successfully made a menu where you can pause the main thread (which just prints "Update" to the console currently.)
Now I've stumbled across a problem and couldn't find an answer.
I plan to make a radio streamer for the top bar and the menu closing on every click would be very undesirable for navigation when searching.
How can I make the menu stay open when clicking an item?
Here is my code:
import os
import signal
import time
from threading import Thread
import gi
gi.require_version("Gtk", "3.0")
gi.require_version("AppIndicator3", "0.1")
from gi.repository import Gtk as gtk
from gi.repository import AppIndicator3 as appindicator
from gi.repository import GObject as gobject
class Indicator:
def __init__(self, name=None, icon=None):
self.path = os.path.abspath(os.path.dirname(__file__))
signal.signal(signal.SIGINT, signal.SIG_DFL)
if name is None:
self.name = "MyApp"
else:
self.name = name
if icon is None:
self.icon = gtk.STOCK_INFO
else:
self.icon = icon
self.indicator = appindicator.Indicator.new(
self.name, self.icon,
appindicator.IndicatorCategory.SYSTEM_SERVICES
)
self.indicator.set_status(appindicator.IndicatorStatus.ACTIVE)
self.indicator.set_menu(self.create_menu())
self.running = True
self.paused = False
self.thread = Thread(target=self.update)
self.thread.setDaemon(True)
self.thread.start()
def create_menu(self):
menu = gtk.Menu()
pause_entry = gtk.MenuItem("Pause")
pause_entry.connect("activate", self.pause)
menu.append(pause_entry)
quit_entry = gtk.MenuItem("Quit")
quit_entry.connect("activate", self.quit)
menu.append(quit_entry)
menu.show_all()
return menu
def update(self):
while self.running:
time.sleep(1)
if not self.paused:
print("Update", flush=True)
def start(self):
gobject.threads_init()
gtk.main()
def pause(self, menu):
self.paused = not self.paused
text = "Resume" if self.paused else "Pause"
for widget in menu.get_children():
print(widget.get_text())
widget.set_text(text)
def quit(self, menu=None):
self.running = False
gtk.main_quit()
if __name__ == "__main__":
indicator = Indicator()
indicator.start()
Unfortunately, I don't think you can make the menu stay open when clicking on an item.
This was an intentional design decision taken by the AppIndicator developers in order to ensure that the indicator would function in a consistent and uniform way and that no custom actions(e.g. right-click, mouseover etc) would be possible to be applied on by end users.
I have created an appindicator that displays news in real time and when I researched the related pygtk/appindicator API reference material; the only allowed supported menu action that I came across was that of scrolling.
With regards to your radio streamer project I suggest have the menu as the main focal point of your application and have the menu items appropriately bidden to pygtk windows. Then use callbacks and signals to perform your necessary actions. This is the approach I undertook in my little project too and turned out pretty nicely.
I am using PyQt5 5.5.1 (64-bit) with Python 3.4.0 (64-bit) on Windows 8.1
64-bit.
I am having trouble restoring the position and size (geometry) of my
very simple PyQt app.
Here is minimal working application:
import sys
from PyQt5.QtWidgets import QApplication, QWidget
class myApp(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
view = myApp()
sys.exit(app.exec())
What I read online is that this is the default behavior and we need to
use QSettings to save and retrieve settings from Windows registry,
which is stored in
\\HKEY_CURRENT_USER\Software\{CompanyName}\{AppName}\
Here are some of the links I read.
I could have followed those tutorials but those tutorials/docs were
written for C++ users.
C++ is not my glass of beer, and converting those codes are impossible to me.
Related:
QSettings(): How to save to current working directory
This should do.
import sys
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtCore import QSettings, QPoint, QSize
class myApp(QWidget):
def __init__(self):
super(myApp, self).__init__()
self.settings = QSettings( 'My company', 'myApp')
# Initial window size/pos last saved. Use default values for first time
self.resize(self.settings.value("size", QSize(270, 225)))
self.move(self.settings.value("pos", QPoint(50, 50)))
def closeEvent(self, e):
# Write window size and position to config file
self.settings.setValue("size", self.size())
self.settings.setValue("pos", self.pos())
e.accept()
if __name__ == '__main__':
app = QApplication(sys.argv)
frame = myApp()
frame.show()
app.exec_()
I simplified this example: QSettings(): How to save to current working directory
Similar to #Valentin's response, because I feel settings are being written to registry, which will be issue for cross compatiblity. Here is the relevant startEvent() and closeEvent() for the job.
def startEvent()
self.settings = QSettings(QSettings.IniFormat,QSettings.SystemScope, '__MyBiz', '__settings')
self.settings.setFallbacksEnabled(False) # File only, not registry or or.
# setPath() to try to save to current working directory
self.settings.setPath(QSettings.IniFormat,QSettings.SystemScope, './__settings.ini')
# Initial window size/pos last saved
self.resize(self.settings.value("size", QSize(270, 225)))
self.move(self.settings.value("pos", QPoint(50, 50)))
self.tab = QWidget()
def closeEvent(self, e):
# Write window size and position to config file
self.settings.setValue("size", self.size())
self.settings.setValue("pos", self.pos())
startEvent() should be initiated at startup and closeEvent() should be taken care before quitting the main window.
You should indeed use QSetting for this.
All the Qt examples have been converted to Python. They are included in the source packages of PyQt (or PySide), which you can download here
You can also look online in the github repo, particularly in application.py of mainwindows example.
def readSettings(self):
settings = QSettings("Trolltech", "Application Example")
pos = settings.value("pos", QPoint(200, 200))
size = settings.value("size", QSize(400, 400))
self.resize(size)
self.move(pos)
def writeSettings(self):
settings = QSettings("Trolltech", "Application Example")
settings.setValue("pos", self.pos())
settings.setValue("size", self.size())
Fire writeSettings() before quitting and initiate readSettings() on startup.
In my case I use .ini files to store settings (language, default user, ...). the same code works on both Debian and Windows.
An example:
from PySide.QtCore import QSettings
self.settings = QSettings('settings.ini', QSettings.IniFormat)
...
self.settings.setValue('size', self.size())
I'm writing in python using Qt
I want to create the application window (with decorations) to occupy the full screen size. Currently this is the code I have:
avGeom = QtGui.QDesktopWidget().availableGeometry()
self.setGeometry(avGeom)
the problem is that it ignores window decorations so the frame is larger... I googled and what not, found this:
http://harmattan-dev.nokia.com/docs/library/html/qt4/application-windows.html#window-geometry
which seems to indicate I need to set the frameGeometry to the avGeom however I haven't found a way to do that. Also, in the comments in the above link it says what I'm after may not be even possible as the programme can't set the frameGeometry before running... If that is the case I just want confirmation that my problem is not solvable.
EDIT:
So I played around with the code a bit and this gives what I want... however the number 24 is basically through trial and error until the window title is visible.... I want some better way to do this... which is window manager independent..
avGeom = QtGui.QDesktopWidget().availableGeometry()
avGeom.setTop(24)
self.setGeometry(avGeom)
Now I can do what I want but purely out of trial and error
Running Ubuntu, using Spyder as an IDE
thanks
Use QtGui.QApplication().desktop().availableGeometry() for the size of the window:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from PyQt4 import QtGui, QtCore
class MyWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.pushButtonClose = QtGui.QPushButton(self)
self.pushButtonClose.setText("Close")
self.pushButtonClose.clicked.connect(self.on_pushButtonClose_clicked)
self.layoutVertical = QtGui.QVBoxLayout(self)
self.layoutVertical.addWidget(self.pushButtonClose)
titleBarHeight = self.style().pixelMetric(
QtGui.QStyle.PM_TitleBarHeight,
QtGui.QStyleOptionTitleBar(),
self
)
geometry = app.desktop().availableGeometry()
geometry.setHeight(geometry.height() - (titleBarHeight*2))
self.setGeometry(geometry)
#QtCore.pyqtSlot()
def on_pushButtonClose_clicked(self):
QtGui.QApplication.instance().quit()
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
app.setApplicationName('MyWindow')
main = MyWindow()
main.show()
sys.exit(app.exec_())
I've always found inheritting from the QMainWindow class to be particularly useful. Like this:
import sys
from PySide.QtGui import *
from PySide.QtCore import *
class Some_APP(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
### this line here is what you'd be looking for
self.setWindowState(Qt.WindowMaximized)
###
self.show()
def main():
app = QApplication(sys.argv)
some_app = Some_APP()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Well, I'm writing a small PyQt4 app, it's just a single Yes/No dialog which has to execute an external command (e.g. 'eject /dev/sr0') and quit.
The app runs, it executes the command after pressing the "Yes" button, but I cannot make the dialog itself exit when executing the command.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
import os
import subprocess
from PyQt4 import QtGui
from PyQt4 import QtCore
from subprocess import call
cmd = 'eject /dev/sr0'
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
btn = QtGui.QPushButton('Yes', self)
btn.clicked.connect(lambda: os.system(cmd))
btn.resize(180, 40)
btn.move(20, 35)
qbtn = QtGui.QPushButton('No', self)
qbtn.clicked.connect(QtCore.QCoreApplication.instance().quit)
qbtn.resize(180, 40)
qbtn.move(20, 80)
self.setWindowTitle('Test')
self.show()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Here is my code. When I click "Yes", it calls the 'eject /dev/sr0' command properly, but after that the dialog is still visible. I have to click "No" to close the app I would like it to close automatically when the command is executed. What should I add/modify?
btn.clicked.connect(self.close)
That would be my suggestion
Replace lambda: os.system(cmd) with a function/method that has multiple statements.
def buttonClicked(self):
os.system(cmd)
QtCore.QCoreApplication.instance().quit()
...
btn = QtGui.QPushButton('Yes', self)
btn.clicked.connect(self.buttonClicked)
...
Step1: in the Main Class needs to be build a "connection":
self.ui.closeButton.clicked.connect(self.closeIt)
Step2: Creating a function like to close:
def closeIt(self):
self.close()
I named to "closeIt" on purpose because if you name it "close" a conflict will occur.
This solution has the advantage if the created GUI is a plugin for another program (like in my case QGIS), only the active GUI will be closed and not the whole program.
Subclass QDialog() and then close it using your object.
class Dialog(QDialog):
"""
Subclassing QDialog class.
"""
def __init__(self):
QDialog.__init__(self)
def close_clicked(self):
self.close()
In your main function write following code
dialogbox = Dialog() # we subclasses QDialog into Dialog
b1= QPushButton("Close",dialogbox)
b1.clicked.connect(dialogbox.close_clicked)
dialogbox.exec_()
I've made a gui in glade that I want to put in a python program. I was adapting the instructions from a tutorial I found online to load in my glade file (http://www.pygtk.org/articles/pygtk-glade-gui/Creating_a_GUI_using_PyGTK_and_Glade.htm). When I had problems I tried something basic (one button) calling it the same thing as in that tutorial, and copy pasting their code, and it still didn't work. I also took a look at (http://www.linuxjournal.com/article/6586?page=0,2), which has a function being called slightly differently ("self.wTree=gtk.glade.XML (gladefile,windowname)" instead of without windowname), and implemented an equivalent with mine and that didn't fix it. I definitely have pygtk working, I made something without using glade before and it worked fine. The error I'm getting is:
/usr/share/themes/NOX/gtk-2.0/gtkrc:233: Murrine configuration option "gradients"
is no longer supported and will be ignored.
(helloWorld.py:9804): libglade-WARNING **: Expected <glade-interface>. Got
<interface>.
(helloWorld.py:9804): libglade-WARNING **: did not finish in PARSER_FINISH state
Traceback (most recent call last):
File "helloWorld.py", line 31, in <module>
hwg = HellowWorldGTK()
File "helloWorld.py", line 22, in __init__
self.wTree = gtk.glade.XML(self.gladefile)
RuntimeError: could not create GladeXML object
I'm running xubuntu 11.04. The Murrine configuration thing comes up when any gtk application opens, but I included it in case it is relevant. Here's the code I took from the tutorial (but isn't working)
#!/usr/bin/env python
import sys
try:
import pygtk
pygtk.require("2.0")
except:
pass
try:
import gtk
import gtk.glade
except:
sys.exit(1)
class HellowWorldGTK:
"""This is an Hello World GTK application"""
def __init__(self):
#Set the Glade file
self.gladefile = "PyHelloWorld.glade"
self.wTree = gtk.glade.XML(self.gladefile)
#Get the Main Window, and connect the "destroy" event
self.window = self.wTree.get_widget("MainWindow")
self.window.show()
if (self.window):
self.window.connect("destroy", gtk.main_quit)
if __name__ == "__main__":
hwg = HellowWorldGTK()
gtk.main()
Try with this code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pygtk
pygtk.require("2.0")
import gtk
import gtk.glade
class HellowWorldGTK:
def __init__(self):
self.gladefile = "helloworld.glade"
self.glade = gtk.Builder()
self.glade.add_from_file(self.gladefile)
self.glade.connect_signals(self)
self.glade.get_object("MainWindow").show_all()
def on_MainWindow_delete_event(self, widget, event):
gtk.main_quit()
if __name__ == "__main__":
try:
a = HellowWorldGTK()
gtk.main()
except KeyboardInterrupt:
pass
Remember:
In Glade, Edit the "Preferences" of the file to "GTKBuilder" (not "libglade")
Your PyHelloWorld.glade is incorrect. Make sure you created it with the correct Glade application, there are Glade2 and Glade3 applications that can be installed and used. If you downloaded the file make sure it is correct. The error message says it all:
Expected <glade-interface>. Got <interface>
So the XML file has the interface tag, but PyGTK library expects glade-interface tag.
Since I always end up having problems with this, here is a Python 2.7 code that I use for one or the other:
for Libglade:
# needs libglade (not for gtk-builder)
import pygtk
pygtk.require("2.0")
import gtk
import gtk.glade
gladefile = "test-libglade.glade"
wTree = gtk.glade.XML(gladefile)
window = wTree.get_widget("MainWindow")
if (window):
window.connect("destroy", gtk.main_quit)
window.show_all() # must have!
gtk.main()
For GtkBuilder:
# needs gtk-builder (not for libglade)
import pygtk
pygtk.require("2.0")
import gtk
gladefile = "test-gtkbuilder.glade"
wTree = gtk.Builder()
wTree.add_from_file(gladefile)
window = wTree.get_object("MainWindow")
if (window):
window.connect("destroy", gtk.main_quit)
window.show_all() # must have!
gtk.main()
In Glade, you can just add a Window, call it MainWindow, and save two versions with the respective filenames as above for each format; and these snippets should work with them respeactively.
Hope this helps someone,
Cheers!
This works perfectly.
#!/usr/bin/python
import pygtk
pygtk.require("2.0")
import gtk
import gtk.glade
class SubinsWindow:
def __init__(self):
self.gladefile = "game.glade"
self.glade = gtk.Builder()
self.glade.add_from_file(self.gladefile)
self.glade.connect_signals(self)
self.win=self.glade.get_object("window1") # Window Name in GLADE
self.win.show_all()
if __name__ == "__main__":
a = SubinsWindow()
gtk.main()
If you are using GTK+3 in python, see builder.
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class Handler:
def onDestroy(self, *args):
Gtk.main_quit()
def onButtonPressed(self, button):
print("Hello World!")
builder = Gtk.Builder()
builder.add_from_file("builder_example.glade")
builder.connect_signals(Handler())
window = builder.get_object("window1")
window.show_all()
Gtk.main()