I know to embed vim in a Gtk application using sockets like the following snippet
from gi.repository import Gtk
import subprocess
win=Gtk.Window()
win.set_default_size(600,800)
win.connect('delete-event', Gtk.main_quit)
editor = Gtk.Socket()
win.add(editor)
editor.connect("plug-removed", Gtk.main_quit)
subprocess.Popen(["/usr/bin/gvim", \
"--socketid", str(editor.get_id())])
win.show_all()
Gtk.main()
How does one do this in PySide? I could not find any reference to sockets in pyside.
UPDATE (using JimP's idea)
The following code embeds a gvim instance in a Pyside widget. However the gvim window does not seem to resize when to the full size of the parent window.
import sys
from PySide import QtGui
from PySide import QtCore
app = QtGui.QApplication(sys.argv)
win = QtGui.QWidget()
win.resize(600, 800)
container = QtGui.QX11EmbedContainer(win)
container.show()
QtCore.QObject.connect(container,
QtCore.SIGNAL("clientClosed()"),
QtCore.QCoreApplication.instance().quit)
winId = container.winId()
process = QtCore.QProcess(container)
options = ["--socketid", str(winId)]
process.start("gvim", options)
win.show()
sys.exit(app.exec_())
I think the key to getting this working would be translating GTK speak to QT speak. Google around your code, I see that Gtk.Socket says:
The communication between a GtkSocket and a GtkPlug follows the XEmbed
protocol. This protocol has also been implemented in other toolkits,
e.g. Qt, allowing the same level of integration when embedding a Qt
widget in GTK or vice versa.
So then the question becomes what does QT call their XEmbed classes? Google around I found QX11EmbedContainer which says:
It is possible for PySide.QtGui.QX11EmbedContainer to embed XEmbed
widgets from toolkits other than Qt, such as GTK+. Arbitrary
(non-XEmbed) X11 widgets can also be embedded, but the XEmbed-specific
features such as window activation and focus handling are then lost.
The GTK+ equivalent of PySide.QtGui.QX11EmbedContainer is GtkSocket.
The corresponding KDE 3 widget is called QXEmbed.
I'm not running PySide at the moment, but that page on QX11EmbedContainer contains some example C++ code that I think will get you where you need to be. You will need to translate the C++ to Python, but I don't that will be too hard.
Related
Note how this application implements a mainloop by the activate signal and .run() method call:
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk
def on_activate(app):
win = Gtk.ApplicationWindow(application=app)
btn = Gtk.Button(label="Hello, World!")
btn.connect('clicked', lambda x: win.close())
win.set_child(btn)
win.present()
app = Gtk.Application(application_id='org.gtk.Example')
app.connect('activate', on_activate)
app.run(None)
Correct me: I think this activate signal is emitted as an event to synchronise the creation of GTK windows, widgets, etc, so that the GUI part does not race to happen before the application is ready. What else is the point?
Then, when the Window, widgets, etc are all drawn, the application gets stuck in a mainloop by .run(). This way the application doesn't exit immediately, but rather waits for user input.
What bothers me here is that I don't see the value of the Application class. Because of it, we got an event on signal activate to tell "oh the app is ready", but what is this app anyway? Why can't I just do .run() on Gtk.ApplicationWindow or even Gtk.Window?
In order to answer those questions above, I invented/discovered this question that, if answered, I think it will address my frustration:
Question: What is the GT4 approach in running GUI apps without using Application or ApplicationWindow classes?
Background
I come from a TKinter background. There, I could make an app simply by saying something like:
import tkinter
class MyApp(tkinter.Tk):
def __init__(self):
super().__init__()
self.title('some title')
if __name__ == '__main__':
myapp = MyApp()
myapp.mainloop()
It feels much simpler, without a spaghetti of creating two objects (like in GTK4) with signals emitting through them just to barely get a .run() mainloop.
But I have to use GTK4 for this project, and Tkinter is not an option. So I have to learn the suitable GTK4 for me.
According to the docs: "GtkApplication is a high-level API for writing applications.
It supports many aspects of writing a GTK application in a convenient fashion, without enforcing a one-size-fits-all model.
Currently, GtkApplication handles GTK initialization, application uniqueness, session management, provides some basic scriptability and desktop shell integration by exporting actions and menus and manages a list of toplevel windows whose life-cycle is automatically tied to the life-cycle of your application.
While GtkApplication works fine with plain GtkWindows, it is recommended to use it together with GtkApplicationWindow."
Source: https://docs.gtk.org/gtk4/class.Application.html
The clasic hello world from Gtk3 will not work on Gtk4
This works:
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
win = Gtk.Window()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
But if you change "3.0" by "4.0" does not work and the reason is on the migration guide:
"GTK 4 removes the gtk_main_* family of APIs. The recommended replacement is GtkApplication"
https://docs.gtk.org/gtk4/migrating-3to4.html#stop-using-gtk_main-and-related-apis
Gtk have a different approach to Tk, you will need to be used to that.
And GTK4 is still new, you will found more examples about Gtk3 code, so, keep the migration guide at hand
I am writing a program on Python 3.4 that uses GTK Map widget (OsmGpsMap) and pygame for joystick input.
Here is a simple program that displays a window with a map:
import gi
from gi.repository import Gtk
from gi.repository import OsmGpsMap
window = Gtk.Window(Gtk.WindowType.TOPLEVEL)
window.connect('destroy', Gtk.main_quit)
map_widget = OsmGpsMap.Map()
window.add(map_widget)
window.show_all()
Gtk.main()
But if I just add a
import pygame
line (without pygame.init() and etc.), the program doesnt launch and I receive a message that python.exe have stopped.
So, how is it possible to fix that?
Do not mix frameworks. The frameworks may interact poorly with each other or conflict completely. If it works on your (operating) system, that doesn't mean it will work on another (operating) system or with a different version of one of the frameworks. Mixing frameworks always means some kind of undefined behavior.
Pygame is based on SDL2, so there is no chance that PyGame can display an osmgpsmap which is a Gtk+ widget.
I have a PySide (Qt) application that utilizes an mdiArea in the main window and then populates this area with a number of QWidgets (windows). These QWidgets have menu bars added to a vertical layout.
This works great on Linux and Windows, but fails on OS X, i.e. only the QMainWindow menu bar is shown. A menubar added to a QWidget that is a sub window of an mdiArea is never displayed. What is the normal method for supporting menubars in sub windows across all platforms? Is it possible to put the menu into a toolbar?
Techniques in python or C++ are appreciated - whether a piece of code or a broader design pattern.
I'm looking for GUI feature that will be part of Python desktop application.
The feature is a text tree with drag and drop functionality between individual nodes.
Further I'd like to be able to attach a note with longer text to individual nodes in the tree. The note would be switchable to expanded or collapsed state.
It is exactly shown in this NestedSortable JQuery library except of the switchable note.
Could you show me what are the possibilities of contemporary Python GUIs according to this feature? I prefer lightweight GUI with modern look as in the JQuery example.
Which GUI would be the most suitable for this task? Tkinter, wxPython, pyQt, pyGTK or other? Or would you choose some GUI + Javascript libraries? Why would you prefer particular GUI to achieve requested functionality and lightweight modern design?
pyQT has a good solution for this with its QTreeWidget or a MVC setup. QTreeWidget is simplest:
Here's a small example using PyQt4
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.treewidget = QTreeWidget(self)
self.treewidget.setHeaderLabels(['a'])
self.treewidget.setDragEnabled(True)
self.treewidget.setAcceptDrops(True)
self.treewidget.setDropIndicatorShown(True)
self.treewidget.resize(300,300)
self.titems = []
for i in xrange(100):
if not i%10:
pitem = QTreeWidgetItem(self.treewidget,["Parent %d"%i])
self.titems.append(pitem)
else:
item = QTreeWidgetItem(pitem,["Child of %d"%i])
self.titems.append(item)
self.show()
app = QApplication(sys.argv)
w = MainWindow()
app.exec_()
Try using etetoolkit. Its much simpler.
I am fairly new to Python programming, and completely new to cross-platform GUI building (only previous GUI experience is through visual basic and Java).
I've written some python code to screen-scrape data from a website, and now I want to build a GUI that will reside in the Mac OS X menubar, and in Window's task bar (i.e., the system tray).
The most useful general page on cross-plaform Python GUIs for me was this one (despite its name indication Window GUIs). And some stackoverflow questions came in useful as well (especially this one, and the accepted answer of this one about splitting up the GUI and cli code).
I think I will go for either wxPython or QT because I want the GUI to look as native as possible.
However, as I've said the fairly simple GUI will mainly live in the taskbar/menubar.
Should this influence my decision?
Here's an example for PyQt. This works for me on MacOS X; I haven't tried it on other platforms. Note that the QSystemTrayIcon class will raise exceptions if it doesn't have an icon – I grabbed the RSS feed svg from Wiki commons for my icon.svg (but you can give QIcon a PNG directly and not mess around with QtSvg).
import PyQt4
from PyQt4 import QtCore, QtGui, QtSvg
app = QtGui.QApplication([])
i = QtGui.QSystemTrayIcon()
m = QtGui.QMenu()
def quitCB():
QtGui.QApplication.quit()
def aboutToShowCB():
print 'about to show'
m.addAction('Quit', quitCB)
QtCore.QObject.connect(m, QtCore.SIGNAL('aboutToShow()'), aboutToShowCB)
i.setContextMenu(m)
svg = QtSvg.QSvgRenderer('icon.svg')
if not svg.isValid():
raise RuntimeError('bad SVG')
pm = QtGui.QPixmap(16, 16)
painter = QtGui.QPainter(pm)
svg.render(painter)
icon = QtGui.QIcon(pm)
i.setIcon(icon)
i.show()
app.exec_()
del painter, pm, svg # avoid the paint device getting
del i, icon # deleted before the painter
del app
See this related SO answer on how to accomplish Windows system tray/OS X menu bar functionality in wxPython.