Strange difference. Why different result in FileChooserDialog? - python

I've battled with the following for a couple of days, and distilled a very compact version of the problem which still shows the issue. The following program shows a basic window, and first opens a FileChooserDialog.
Here's the version which fails - it does not show the Cancel and Accept buttons in the dialog:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import GLib, Gtk
class Script():
def __init__(self, parent, width = 800):
self.parent = parent
def script_file_dialog(self):
fc = Gtk.FileChooserDialog(
parent = self.parent,
title = "title",
action = Gtk.FileChooserAction.OPEN,
do_overwrite_confirmation = True)
fc.add_buttons = ("Cancel", Gtk.ResponseType.CANCEL,
"Open", Gtk.ResponseType.ACCEPT)
return fc
class MainWindow(Gtk.Window):
def __init__(self):
super(MainWindow, self).__init__()
self.connect("destroy", lambda x: Gtk.main_quit())
self.set_default_size(1000, 580)
self.script = Script(self)
fc = self.script.script_file_dialog()
if fc.run() == 1:
print("one")
fc.destroy()
self.show_all()
def on_test_clicked(self, btn):
#~ self.script.on_open_script(btn)
self.script = Script(self)
fc = self.script.script_file_dialog()
if fc.run() == 1:
print("one")
fc.destroy()
def run(self):
Gtk.main()
def main(args):
mainwdw = MainWindow()
mainwdw.run()
return 0
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))
And the following, almost identical version does work as intended.
Note the only difference is when instancing the FileChooserDialog,
the buttons are passed as keyword parameters. This is deprecated, and
produces a warning.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import GLib, Gtk
class Script():
def __init__(self, parent, width = 800):
self.parent = parent
def script_file_dialog(self):
fc = Gtk.FileChooserDialog(
parent = self.parent,
title = "title",
action = Gtk.FileChooserAction.OPEN,
do_overwrite_confirmation = True,
buttons = ("Cancel", Gtk.ResponseType.CANCEL,
"Open", Gtk.ResponseType.ACCEPT))
return fc
class MainWindow(Gtk.Window):
def __init__(self):
super(MainWindow, self).__init__()
self.connect("destroy", lambda x: Gtk.main_quit())
self.set_default_size(1000, 580)
self.script = Script(self)
fc = self.script.script_file_dialog()
if fc.run() == 1:
print("one")
fc.destroy()
self.show_all()
def on_test_clicked(self, btn):
#~ self.script.on_open_script(btn)
self.script = Script(self)
fc = self.script.script_file_dialog()
if fc.run() == 1:
print("one")
fc.destroy()
def run(self):
Gtk.main()
def main(args):
mainwdw = MainWindow()
mainwdw.run()
return 0
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))
I tried delaying the showing of the dialog by triggering it by a button
after the main dialog was shown. What's more, I've used the first pattern
in other programs, and it's working there.
It's probably the stay-at-home rules which are slowly getting me crazy...
Anyone sees the problem?

The first version has a typo:
fc.add_buttons = ("Cancel", Gtk.ResponseType.CANCEL,
"Open", Gtk.ResponseType.ACCEPT)
should be:
fc.add_buttons("Cancel", Gtk.ResponseType.CANCEL,
"Open", Gtk.ResponseType.ACCEPT)

Related

python Gtk3 - Set label of button to default value of None

I am trying to reset a label of a button to its initial (default) value of None, which does not work as expected. Here's the minimal example:
from gi import require_version
require_version('Gtk', '3.0')
from gi.repository import Gtk
class GUI(Gtk.Window):
def __init__(self):
super().__init__()
self.connect('destroy', Gtk.main_quit)
self.set_position(Gtk.WindowPosition.CENTER)
self.grid = Gtk.Grid(hexpand=True, vexpand=True)
self.add(self.grid)
button = Gtk.Button(hexpand=True, vexpand=True)
self.grid.attach(button, 0, 0, 1, 1)
button.connect('clicked', self.on_button_clicked)
def on_button_clicked(self, button: Gtk.Button) -> None:
print(label := button.get_label(), type(label))
button.set_label(label)
def main() -> None:
win = GUI()
win.show_all()
Gtk.main()
if __name__ == '__main__':
main()
Result:
$ python example.py
None <class 'NoneType'>
Traceback (most recent call last):
File "/home/neumann/example.py", line 21, in on_button_clicked
button.set_label(label)
TypeError: Argument 1 does not allow None as a value
What's the correct way to do this?
Note: Before somebody suggests it: I do not want to set the label to an empty string, since that will change the size of the button, which is noticeable on a larger grid of buttons:
from gi import require_version
require_version('Gtk', '3.0')
from gi.repository import Gtk
class GUI(Gtk.Window):
def __init__(self):
super().__init__()
self.connect('destroy', Gtk.main_quit)
self.set_position(Gtk.WindowPosition.CENTER)
self.grid = Gtk.Grid(hexpand=True, vexpand=True)
self.add(self.grid)
for x in range(3):
button = Gtk.Button(hexpand=True, vexpand=True)
button.connect('clicked', self.on_button_clicked)
self.grid.attach(button, x, 0, 1, 1)
def on_button_clicked(self, button: Gtk.Button) -> None:
print(label := button.get_label(), type(label))
button.set_label('')
def main() -> None:
win = GUI()
win.show_all()
Gtk.main()
if __name__ == '__main__':
main()
I'm not sure what your use case is, but you can try adding a GtkLabel child and set the string there:
from gi import require_version
require_version('Gtk', '3.0')
from gi.repository import Gtk
class GUI(Gtk.Window):
def __init__(self):
super().__init__()
self.connect('destroy', Gtk.main_quit)
self.set_position(Gtk.WindowPosition.CENTER)
self.grid = Gtk.Grid(hexpand=True, vexpand=True)
self.add(self.grid)
for x in range(3):
button = Gtk.Button(hexpand=True, vexpand=True)
label = Gtk.Label()
button.add(label)
button.connect('clicked', self.on_button_clicked)
self.grid.attach(button, x, 0, 1, 1)
def on_button_clicked(self, button: Gtk.Button) -> None:
label = button.get_child()
print(text := label.get_label(), type(text))
label.set_label('')
# or hide it if you want
# label.hide()
def main() -> None:
win = GUI()
win.show_all()
Gtk.main()
if __name__ == '__main__':
main()
GtkButton may be creating the internal GtkLabel child only when a label is set (which should be a valid string). And since the hexpand and vexpand for the GtkButton are set to True, they may be getting propagated to the internal GtkLabel.
If you simply want all the buttons to have same width and height, you may only need grid.set_row_homogeneous() and grid.set_column_homogeneous()

Create Flap in GTK 4 with PyGObject, Libadwaita

I'm trying to create a Flap in Libadwaita using PyGObject but I only get an empty window.
My code looks like this:
import gi
gi.require_version(namespace='Gtk', version='4.0')
gi.require_version(namespace='Adw', version='1')
from gi.repository import Gio, Gtk
from gi.repository import Adw
class MainWindow(Gtk.ApplicationWindow):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.set_title(title='Python and GTK 4 Adwaita: PyGObject Adw.Flap')
box = Gtk.Box()
self.set_child(child=box)
adw_flap = Adw.Flap.new()
self.set_child(child=adw_flap)
class Application(Gtk.Application):
def __init__(self):
super().__init__(application_id='adw.flap.demo',
flags=Gio.ApplicationFlags.FLAGS_NONE)
def do_startup(self):
Gtk.Application.do_startup(self)
def do_activate(self):
win = self.props.active_window
if not win:
win = MainWindow(application=self)
win.present()
def do_shutdown(self):
Gtk.Application.do_shutdown(self)
if __name__ == '__main__':
import sys
app = Application()
app.run(sys.argv)
I'm creating a GTK window with a box inside (do I need to create the box or can I place the flap directly inside the GTK window?) and inside the box I'm trying to create the flap. Where am I going wrong in my code?
I made an example using Adw.Flap() together with Gtk.StackSidebar().
# -*- coding: utf-8 -*-
"""Python e GTK 4: PyGObject Adw.Flap()."""
import gi
gi.require_version(namespace='Gtk', version='4.0')
gi.require_version(namespace='Adw', version='1')
from gi.repository import Gio, Gtk
from gi.repository import Adw
class MainWindow(Gtk.ApplicationWindow):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.set_title(title='Python e GTK 4: PyGObject Adw.Flap()')
self.set_default_size(width=int(1366 / 2), height=int(768 / 2))
self.set_size_request(width=int(1366 / 2), height=int(768 / 2))
vbox = Gtk.Box.new(orientation=Gtk.Orientation.VERTICAL, spacing=12)
self.set_child(child=vbox)
headerbar = Gtk.HeaderBar.new()
self.set_titlebar(titlebar=headerbar)
# Botão que abre e fecha o Flap.
flap_Toggle_button = Gtk.ToggleButton.new()
flap_Toggle_button.set_icon_name(icon_name='sidebar-show-right-rtl-symbolic')
flap_Toggle_button.connect('clicked', self.on_flap_button_toggled)
headerbar.pack_start(child=flap_Toggle_button)
self.adw_flap = Adw.Flap.new()
self.adw_flap.set_reveal_flap(reveal_flap=False)
self.adw_flap.set_locked(locked=True)
vbox.append(child=self.adw_flap)
stack = Gtk.Stack.new()
self.adw_flap.set_content(content=stack)
# Página 1
box_page_1 = Gtk.Box.new(orientation=Gtk.Orientation.VERTICAL, spacing=6)
stack.add_titled(child=box_page_1, name='pagina1', title='Página 1')
label_page_1 = Gtk.Label.new(str='Página 1')
label_page_1.set_halign(align=Gtk.Align.CENTER)
label_page_1.set_valign(align=Gtk.Align.CENTER)
label_page_1.set_hexpand(expand=True)
label_page_1.set_vexpand(expand=True)
box_page_1.append(child=label_page_1)
# Página 2
box_page_2 = Gtk.Box.new(orientation=Gtk.Orientation.VERTICAL, spacing=6)
stack.add_titled(child=box_page_2, name='pagina2', title='Página 2')
label_page_2 = Gtk.Label.new(str='Página 2')
label_page_2.set_halign(align=Gtk.Align.CENTER)
label_page_2.set_valign(align=Gtk.Align.CENTER)
label_page_2.set_hexpand(expand=True)
label_page_2.set_vexpand(expand=True)
box_page_2.append(child=label_page_2)
# StackSidebar gerencia a troca entre os stack.
stack_sidebar = Gtk.StackSidebar.new()
stack_sidebar.set_stack(stack=stack)
self.adw_flap.set_flap(flap=stack_sidebar)
def on_flap_button_toggled(self, widget):
self.adw_flap.set_reveal_flap(not self.adw_flap.get_reveal_flap())
class Application(Adw.Application):
def __init__(self):
super().__init__(application_id='br.natorsc.Exemplo',
flags=Gio.ApplicationFlags.FLAGS_NONE)
def do_startup(self):
Gtk.Application.do_startup(self)
def do_activate(self):
win = self.props.active_window
if not win:
win = MainWindow(application=self)
win.present()
def do_shutdown(self):
Gtk.Application.do_shutdown(self)
if __name__ == '__main__':
import sys
app = Application()
app.run(sys.argv)
The code used as an example is in my repository:
https://github.com/natorsc/gui-python-gtk.
Whenever possible I am adding new examples.

Making GStreamer video/audio in Python smooth and loop

I'm trying to use GStreamer to loop MPEG-4 files smoothly. I want to play the video and audio if there is any and loop the playback. My app uses GTK for UI.
Right now I have three problems:
The video playback is choppy/jerky on the Raspberry Pi 4, I'm running it on. By choppy/jerky, I mean that every ~1-2 seconds, playback freezes for some fraction of a second. When playing the same video in the VLC app, it is smooth.
Audio is not played. Again, when played in VLC, the audio is there as expected. It was my understanding that playbin elements automatically play both audio and video.
When the end of the video is reached, the last frame is frozen for 1-2 seconds before the video starts playing from the first frame again.
I currently have the following code.
video_player.py:
#!/usr/bin/python3
import os
import gi
gi.require_version("Gst", "1.0")
gi.require_version("Gtk", "3.0")
gi.require_version("GstVideo", "1.0")
from gi.repository import Gst, Gtk, GstVideo
class VideoPlayer(Gtk.DrawingArea):
def __init__(self, video_uri: str, loop: bool):
super().__init__()
self.__loop = loop
self.__video_uri = "file:///" + os.path.abspath(video_uri)
self.__xid = None
Gst.init(None)
self.connect("realize", self.__on_realize)
self.set_size_request(1920, 1080) # Hardcoded for this example
self.__playbin = Gst.ElementFactory.make("playbin", "player")
self.__bus = self.__playbin.get_bus()
self.__bus.add_signal_watch()
self.__bus.connect("message::eos", self.__on_video_end)
self.__bus.enable_sync_message_emission()
self.__bus.connect("sync-message::element", self.__on_sync_message)
self.__playbin.set_property("uri", self.__video_uri)
def __on_realize(self, widget: Gtk.Window, data=None) -> None:
window = widget.get_window()
self.__xid = window.get_xid()
def __on_sync_message(self, bus: Gst.Bus, message: Gst.Message) -> None:
if message.get_structure().get_name() == "prepare-window-handle":
image_sink = message.src
image_sink.set_property("force-aspect-ratio", True)
image_sink.set_window_handle(self.__xid)
def __on_video_end(self, bus: Gst.Bus, message: Gst.Message) -> None:
if self.__loop:
self.__playbin.set_state(Gst.State.NULL)
self.__playbin.set_state(Gst.State.PLAYING)
def play(self) -> None:
if self.__playbin.get_state(0).state != Gst.State.PLAYING:
self.__playbin.set_state(Gst.State.PLAYING)
main.py:
#!/usr/bin/python3
from video_player import VideoPlayer
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
window = Gtk.Window()
video_player = VideoPlayer("test_video.mp4", loop=True)
window.add(video_player)
window.fullscreen()
window.show_all()
video_player.play()
Gtk.main()
This answer provides an example that uses VLC; This was accepted by the author of the question (see comments) - GStreamer on Raspberry Pi 4 and other similar SOCs is often times laggy and a soft solution, without starting to modify the Gstreamer library, is probably not going to help the OP.
Please notice that the code has been inspired by https://www.codementor.io/#princerapa/python-media-player-vlc-gtk-favehuy2b but has been modified to accommodate for your needs.
The required change to make the video loop, which is not provided in the aforementioned link is passing the argument '--input-repeat=-1' to the vlcinstance.
Install dependencies (this assumes you already have gtk installed)
pip install python-vlc
Your code:
import sys
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
gi.require_version('GdkX11', '3.0')
from gi.repository import GdkX11
import vlc
MRL = "" # File to play
WIDTH = 300
HEIGHT = 300
class ApplicationWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Python-Vlc Media Player")
self.player_paused=False
self.is_player_active = False
self.connect("destroy",Gtk.main_quit)
def show(self):
self.show_all()
def setup_objects_and_events(self):
self.playback_button = Gtk.Button()
self.stop_button = Gtk.Button()
self.play_image = Gtk.Image.new_from_icon_name(
"gtk-media-play",
Gtk.IconSize.MENU
)
self.pause_image = Gtk.Image.new_from_icon_name(
"gtk-media-pause",
Gtk.IconSize.MENU
)
self.stop_image = Gtk.Image.new_from_icon_name(
"gtk-media-stop",
Gtk.IconSize.MENU
)
self.playback_button.set_image(self.play_image)
self.stop_button.set_image(self.stop_image)
self.playback_button.connect("clicked", self.toggle_player_playback)
self.stop_button.connect("clicked", self.stop_player)
self.draw_area = Gtk.DrawingArea()
self.draw_area.set_size_request(WIDTH,HEIGHT)
self.draw_area.connect("realize",self._realized)
self.hbox = Gtk.Box(spacing=6)
self.hbox.pack_start(self.playback_button, True, True, 0)
self.hbox.pack_start(self.stop_button, True, True, 0)
self.vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self.add(self.vbox)
self.vbox.pack_start(self.draw_area, True, True, 0)
self.vbox.pack_start(self.hbox, False, False, 0)
def stop_player(self, widget, data=None):
self.player.stop()
self.is_player_active = False
self.playback_button.set_image(self.play_image)
def toggle_player_playback(self, widget, data=None):
"""
Handler for Player's Playback Button (Play/Pause).
"""
if self.is_player_active == False and self.player_paused == False:
self.player.play()
self.playback_button.set_image(self.pause_image)
self.is_player_active = True
elif self.is_player_active == True and self.player_paused == True:
self.player.play()
self.playback_button.set_image(self.pause_image)
self.player_paused = False
elif self.is_player_active == True and self.player_paused == False:
self.player.pause()
self.playback_button.set_image(self.play_image)
self.player_paused = True
else:
pass
def _realized(self, widget, data=None):
self.vlcInstance = vlc.Instance("--no-xlib", "--input-repeat=-1")
self.player = self.vlcInstance.media_player_new()
win_id = widget.get_window().get_xid()
self.player.set_xwindow(win_id)
self.player.set_mrl(MRL)
self.player.play()
self.playback_button.set_image(self.pause_image)
self.is_player_active = True
if __name__ == '__main__':
if not sys.argv[1:]:
print("Exiting \nMust provide the MRL.")
sys.exit(1)
if len(sys.argv[1:]) == 1:
MRL = sys.argv[1]
window = ApplicationWindow()
window.setup_objects_and_events()
window.show()
Gtk.main()
window.player.stop()
window.vlcInstance.release()

How to set QPlainTextEdit verticalScrollBar to maximum?

Consider this mcve:
import sys
from datetime import datetime
from PyQt5.Qt import * # noqa
class Foo(QPlainTextEdit):
def __init__(self, parent=None):
super().__init__(parent)
def keyPressEvent(self, event):
if event.key() == Qt.Key_P:
self.appendPlainText(f"New line")
super().keyPressEvent(event)
class FooWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
m = self.menuBar().addMenu("&Debug")
action = QAction("Baz", self)
action.triggered.connect(self.bar)
action.setShortcut("Ctrl+N")
m.addAction(action)
self.obj = Foo()
self.obj.setLineWrapMode(QPlainTextEdit.NoWrap)
for i in range(20):
self.obj.appendPlainText(f"Line_{i}" * 10)
self.obj_dock = QDockWidget('Console', self)
self.obj_dock.setWidget(self.obj)
self.addDockWidget(Qt.BottomDockWidgetArea, self.obj_dock)
def bar(self):
self.obj.appendPlainText(f"New line from menu action")
def showEvent(self, event):
bar = self.obj.verticalScrollBar()
bar.setValue(bar.maximum())
print(f"2) showEvent {now()}")
def now():
return datetime.utcnow().strftime('%H:%M:%S.%f')[:-3]
if __name__ == "__main__":
app = QApplication(sys.argv)
ex = FooWindow()
print(f"1) before show {now()}")
ex.show()
print(f"3) after show {now()}")
# ex.obj.ensureCursorVisible()
bar = ex.obj.horizontalScrollBar()
bar.setValue(bar.minimum())
bar = ex.obj.verticalScrollBar()
bar.setValue(bar.maximum())
print(f"4) manual bar.setValue {now()}")
# timer = QTimer()
# timer.setInterval(10)
# timer.setSingleShot(True)
# def set_scrollbar_at_maximum():
# bar = ex.obj.verticalScrollBar()
# bar.setValue(ex.obj.verticalScrollBar().maximum())
# print(f"5) bar.setValue from timer {now()}")
# timer.timeout.connect(set_scrollbar_at_maximum)
# timer.start()
sys.exit(app.exec_())
I'd like to view the last lines added without having to scroll the vertical bar down manually. Calling bar.setValue(ex.obj.verticalScrollBar().maximum()) after either ex.show() or def showEvent(self, event): don't work, ie:
Thing is, unless I scroll the vertical bar down manually or I set the value using a single-shot timer the last added lines won't be visible.
I'd like to know why my above snippet isn't working properly and I'd like to know a best alternative to these single-shot timers with random little intervals... Said otherwise, what's the proper place that will guarantee the child widgets will be painted properly after using functions such as setValue. This stuff is pretty confusing, one would expect the showEvent to be a proper place to do so... but it's not :/
As an alternative to use single-shot timers to guarantee the widgets will be painted properly, it seems overriding QMainWindow::event is a good choice, here's a possible solution to the problem:
import sys
from datetime import datetime
from PyQt5.Qt import * # noqa
class Foo(QPlainTextEdit):
def __init__(self, parent=None):
super().__init__(parent)
def keyPressEvent(self, event):
if event.key() == Qt.Key_P:
self.appendPlainText(f"New line")
super().keyPressEvent(event)
class FooWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
m = self.menuBar().addMenu("&Debug")
action = QAction("Baz", self)
action.triggered.connect(self.bar)
action.setShortcut("Ctrl+N")
m.addAction(action)
self.obj = Foo()
self.obj.setLineWrapMode(QPlainTextEdit.NoWrap)
for i in range(20):
self.obj.appendPlainText(f"Line_{i}" * 10)
self.obj_dock = QDockWidget('Console', self)
self.obj_dock.setWidget(self.obj)
self.addDockWidget(Qt.BottomDockWidgetArea, self.obj_dock)
self.window_shown = False
def bar(self):
self.obj.appendPlainText(f"New line from menu action")
def update_widgets(self):
if self.window_shown:
return
bar = ex.obj.horizontalScrollBar()
bar.setValue(bar.minimum())
bar = self.obj.verticalScrollBar()
bar.setValue(bar.maximum())
self.window_shown = True
def event(self, ev):
ret_value = super().event(ev)
if ev.type() == QEvent.Paint:
self.update_widgets()
return ret_value
if __name__ == "__main__":
app = QApplication(sys.argv)
ex = FooWindow()
ex.show()
sys.exit(app.exec_())

Ctreate two or more panel indicator using python gtk3 appindicator

I want to create two or more panel indicator using a single indicator class. This is the code:
#!/usr/bin/env python
import os
from gi.repository import Gtk
from gi.repository import AppIndicator3
class IndicatorObject:
def create_indicator(self, indicator_id):
indicator = AppIndicator3.Indicator.new(indicator_id, os.path.abspath('sample_icon.svg'), AppIndicator3.IndicatorCategory.SYSTEM_SERVICES)
indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)
menu = Gtk.Menu()
item_quit = Gtk.MenuItem('Quit')
menu.append(item_quit)
indicator.set_menu(menu)
menu.show_all()
print indicator_id
indicator1 = IndicatorObject()
indicator1.create_indicator("first_indicator")
indicator2 = IndicatorObject()
indicator2.create_indicator("second_indicator")
Gtk.main()
But nothing happens when i run the script. How can i create two or more indicator using single class?
#!/usr/bin/env python
import os
from gi.repository import Gtk
from gi.repository import AppIndicator3
class AppIndicatorExample:
def __init__(self, indicator_id):
self.ind = AppIndicator3.Indicator.new(str(indicator_id), os.path.abspath('sample_icon.svg'), AppIndicator3.IndicatorCategory.SYSTEM_SERVICES)
self.ind.set_status(AppIndicator3.IndicatorStatus.ACTIVE)
# create a menu
self.menu = Gtk.Menu()
item = Gtk.MenuItem(str(indicator_id))
item.show()
self.menu.append(item)
image = Gtk.ImageMenuItem(Gtk.STOCK_QUIT)
image.connect("activate", self.quit)
image.show()
self.menu.append(image)
self.menu.show()
self.ind.set_menu(self.menu)
def quit(self, widget, data=None):
Gtk.main_quit()
if __name__ == "__main__":
indicator = AppIndicatorExample(1)
indicator2 = AppIndicatorExample(2)
indicator3 = AppIndicatorExample(3)
indicator4 = AppIndicatorExample(4)
indicator5 = AppIndicatorExample(5)
indicator6 = AppIndicatorExample(6)
indicator7 = AppIndicatorExample(7)
indicator8 = AppIndicatorExample(8)
Gtk.main()
This is the right way to using single class to create one or more appindicator.

Categories