How am I supposed to set a Gtk Notebook page tab expandable? - python

When I add a page to a Gtk.Notebook programatically, I can't find a way to set the tab to expand. The property is available in Glade, so I know it can be done. Here is a snippet using reorderable and detachable properties.
#!/usr/bin/env python
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class GUI:
def __init__(self):
window = Gtk.Window()
notebook = Gtk.Notebook()
window.add(notebook)
for i in range (4):
label = Gtk.Label('label in page number ' + str(i))
tab_label = Gtk.Label('page ' + str(i))
notebook.append_page(label, tab_label)
notebook.set_tab_detachable(label, True)
notebook.set_tab_reorderable(label, True)
window.show_all()
window.connect('destroy', Gtk.main_quit)
app = GUI()
Gtk.main()
However,
notebook.set_tab_expandable(label, True)
fails with
AttributeError: 'Notebook' object has no attribute 'set_tab_expandable'

The solution is:
notebook.child_set_property(label, 'tab-expand', True)

Related

PyGTK entry.set_placeholder_text doesnt work - missing tex

I am attaching a piece of my code in which I try to display the text in the Entry field with predefined text. I use entry.set_placeholder_text for this, but unfortunately the text does not appear.
Is there an effective solution?
# -*- coding: utf-8 -*-
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
super(MyWindow, self).__init__()
entry = Gtk.Entry()
entry.set_placeholder_text("Any text")
self.add(entry)
win = MyWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
The placeholder text is only visible when the entry is empty and unfocused. Adding another widget that can get the focus will make the text appear.
Example:
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
super(MyWindow, self).__init__()
entry = Gtk.Entry()
entry.set_placeholder_text("Any text")
box = Gtk.HBox()
self.add(box)
button = Gtk.Button()
box.pack_start(button, False, False, 0)
box.pack_start(entry, True, True, 0)
win = MyWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
I know, I have no idea why it doesn't work.
I usually do:
search_entry.props.placeholder_text = 'Placeholder text'
before calling set_active on the widget

Python GTK+ 3 - Can't set a parent on a toplevel widget

Gtk-WARNING **: 19:18:52.313: Can't set a parent on a toplevel widget
Why do I get this warning? Isn't master win a toplevel widget? What am I doing wrong?
Shouldn't master_win be toplevel? It is created first...
class PluginWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Stack Demo")
#some stuff
master_win = Gtk.ScrolledWindow()
master_win.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS)
win = PluginWindow()
master_win.add(win)
win.connect("destroy", Gtk.main_quit)
master_win.show_all()
Gtk.main()
You have the order wrong
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class PluginWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Stack Demo")
#some stuff
master_win = Gtk.ScrolledWindow()
master_win.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS)
win = PluginWindow()
win.add(master_win)
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
You're trying to add a Gtk.Window() object into Gtk.ScrolledWindow() object and that is not possible. It's inversed.
A Gtk.Window is a toplevel window which can contain other widgets. Windows normally have decorations that are under the control of the windowing system and allow the user to manipulate the window (resize it, move it, close it,…).
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class PluginWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Stack Demo")
# some stuff
master_win = Gtk.ScrolledWindow()
master_win.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS)
win = PluginWindow()
# Gtk.ScrolledWindow added to Gtk.Window
win.add(master_win)
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()

Is `Gtk.Window.set_attached_to` really the correct way to position a popup relative to a widget in wayland?

set_attached_to seems to be the correct way to position a popup window relative to a widget in wayland:
Examples of places where specifying this relation is useful are for instance [...] a completion popup window created by Gtk.Entry [...]
Unfortunately this only yields an error
Gdk-Message: 12:13:16.143: Window 0x1822340 is a temporary window without parent, application will not be able to position it on screen.
Trying to uncomment the popup.set_parent(entry) line only adds a warning:
(try_entry_popup.py:4539): Gtk-WARNING **: 12:17:34.185: Can't set a parent on a toplevel widget
followed by the same error.
Here is a minimal example:
#!/usr/bin/env python
# stripped down from https://gitlab.gnome.org/GNOME/gtk/issues/1541#note_396391
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
entry = Gtk.Entry()
popup = Gtk.Window(type=Gtk.WindowType.POPUP)
#popup.set_parent(entry)
popup.set_attached_to(entry)
popup.show_all()
layout = Gtk.VBox()
layout.pack_start(entry, False, True, 0)
window = Gtk.Window()
window.connect("destroy", Gtk.main_quit)
window.add(layout)
window.show_all()
Gtk.main()
From the entry completion source it looks like it definitely should work.
Is it using private features ? Or what am I missing ?
Well, not really: gtk_window_set_attached_to has nothing to do with positioning, it's important for accessibility (a11y) and to apply theming in a correct way. If you want to position your popup window you can follow what it's done in https://gitlab.gnome.org/GNOME/gtk/blob/075dcc142aa525778268165095de019b736f3efa/gtk/gtkentrycompletion.c#L1597
Here's a very simple implementation:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
def on_button_clicked(widget):
popup = Gtk.Window(type=Gtk.WindowType.POPUP)
# optionally you may set an appropriate type hint, but it's not required.
popup.set_attached_to(entry)
popup.set_transient_for(window)
gdk_window = entry.get_window()
gdk_window_origin = gdk_window.get_origin()
x = gdk_window_origin[1]
y = gdk_window_origin[2]
allocation = entry.get_allocation()
x += allocation.x
y += allocation.y + allocation.height
popup.move(x, y)
popup.show_all()
button = Gtk.Button()
button.connect('clicked', on_button_clicked)
entry = Gtk.Entry()
layout = Gtk.VBox()
layout.pack_start(button, False, True, 0)
layout.pack_start(entry, False, True, 0)
window = Gtk.Window()
window.connect("destroy", Gtk.main_quit)
window.add(layout)
window.show_all()
Gtk.main()

Grab keyboard on XEmbed window

I'm trying to migrate open source application written in PyQt4 to Qt5 (PyQt5 or PySide2) and I have a problem with migration of QtGui.QX11EmbedContainer to Qt5. It looks that XEmbed container created with QtWidgets.QWidget.createWindowContainer cannot grab keyboard properly.
In Qt4 it was possible to grab keyboard in such way (for simplicity I'll attach xterm):
import sys
from PyQt4 import QtGui, QtCore
def clientEmbed():
container.grabKeyboard()
print("Keyboard grabbed")
def clientClosed():
container.releaseKeyboard()
print("Keyboard released")
app = QtGui.QApplication(sys.argv)
mainWidget = QtGui.QWidget()
container = QtGui.QX11EmbedContainer(mainWidget)
container.clientIsEmbedded.connect(clientEmbed)
container.clientClosed.connect(clientClosed)
vBoxLayout = QtGui.QVBoxLayout()
vBoxLayout.addWidget(container)
mainWidget.setLayout(vBoxLayout)
process = QtCore.QProcess(container)
winId = container.winId()
mainWidget.show()
process.start("xterm", "-into {} -xrm xterm*.allowSendEvents:true".format(winId).split())
sys.exit(app.exec_())
In this case any key event was sent to xterm, but in Qt5 analogous code doesn't work properly and xterm doesn't receives any key events:
import sys
from PyQt5 import QtWidgets, QtGui, QtCore
app = QtWidgets.QApplication(sys.argv)
def processStarted():
container.grabKeyboard()
print("Process started")
mainWidget = QtWidgets.QWidget()
mainWidget.showMaximized()
window = QtGui.QWindow()
container = QtWidgets.QWidget.createWindowContainer(window, mainWidget)
vBoxLayout = QtWidgets.QVBoxLayout()
vBoxLayout.addWidget(container)
mainWidget.setLayout(vBoxLayout)
mainWidget.show()
winId = int(window.winId())
process = QtCore.QProcess(container)
process.started.connect(processStarted)
process.start("xterm", "-into {} -xrm xterm*.allowSendEvents:true".format(winId).split())
sys.exit(app.exec_())
At this time I'm considering migration from Qt4 to GTK3 which plays nice with grabbing keyboard on XEmbed, but it will be more time consuming. For example analogous working code in PyGTK:
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk
from subprocess import Popen
def plugged_added(plugged_socket):
Gdk.Seat.grab(seat, plugged_socket.get_window(), Gdk.SeatCapabilities.KEYBOARD, True)
print("xterm attached")
def plugged_removed(plugged_socket):
Gdk.Seat.ungrab(seat)
print("xterm detached")
seat = Gdk.Display.get_default().get_default_seat()
window = Gtk.Window(title="Xterm embed")
socket = Gtk.Socket()
window.add(socket)
sock_id = str(socket.get_id())
socket.connect("plug-added", plugged_added)
socket.connect("plug-removed", plugged_removed)
cmd = ["xterm", '-xrm', "xterm*.allowSendEvents: true", "-into", sock_id]
Popen(cmd)
socket.show()
window.show()
window.connect("destroy", Gtk.main_quit)
Gtk.main()
So does anybody have idea how to achieve grabbing keyboard in Qt5 like it is possible in Qt4 or PyGTK3? I'm also opened to solutions including xlib, xcb etc.

How to show numbers as super script on a gobject app indicator icon?

I have a working app indicator that looks something like this i.e text as label beside the app indicator icon -
I wanted to know if it is possible to get it to look like this i.e number on the icon as a superscript-
Sample code for the app indicator -
import random
from gi.repository import Gtk, GLib
from gi.repository import AppIndicator3 as appindicator
APPINDICATOR_ID = 'myappindicator'
def cb_exit(w, data):
Gtk.main_quit()
def change_label(ind_app):
t = random.randint(1,6)
print(t)
ind_app.set_label(str(t) , '')
ind_app = appindicator.Indicator.new(APPINDICATOR_ID, Gtk.STOCK_INFO, appindicator.IndicatorCategory.SYSTEM_SERVICES)
ind_app.set_status(appindicator.IndicatorStatus.ACTIVE)
# create a menu
menu = Gtk.Menu()
menu_items = Gtk.MenuItem("Exit")
menu.append(menu_items)
menu_items.connect("activate", cb_exit, '')
menu_items.show_all()
ind_app.set_menu(menu)
GLib.timeout_add(1000, change_label, ind_app)
Gtk.main()
If it is indeed possible, then how?

Categories