How to allow only one instance of a certain class?

Asked

Viewed 271 times

4

If we execute the code below, a window will be created with a button inside, that every clicked will open another window (Window2)... How do I not allow a second instance of Window2? I want to do this without using modal().

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from gi.repository import Gtk

class Main(Gtk.Window):
    def __init__(self):
        button = Gtk.Button('Click')
        Gtk.Window.__init__(self, title = 'Main Window')
        button.connect('clicked', Window2)
        self.connect('delete-event', Gtk.main_quit)
        self.set_default_size(300, 200)
        self.add(button)
        self.show_all()

class Window2(Gtk.Window):
    def __init__(self, widget):
        button = Gtk.Button('Exit')
        Gtk.Window.__init__(self, title = 'Window2')
        button.connect('clicked', Gtk.main_quit)
        self.set_default_size(300, 200)
        self.add(button)
        self.show_all()


if __name__ == '__main__':
    Main()
    Gtk.main()
  • 5

    Read this Design Pattern: http://pt.wikipedia.org/wiki/Singleton so you can adapt your code to Singleton

  • @Diegovieira In this particular case, I don’t think you need to use Singleton (just change the behavior of the button), but if you want to give an answer covering the general case, feel free! (by title, this question is likely to attract many visitors.. P)

3 answers

3


In the general case, one answer is to use Singleton, as pointed out by Diego Vieira in the comments. In your specific case, I believe that just change the behavior of the button to not create a window every time:

class Main(Gtk.Window):
    def __init__(self):
        self.window2 = None     # Cria-se uma referência no self para a janela

        button = Gtk.Button('Click')
        Gtk.Window.__init__(self, title = 'Main Window')
        button.connect('clicked', self.mostrar_janela)    # Mostra-a quando clicar no botão
        self.connect('delete-event', Gtk.main_quit)
        self.set_default_size(300, 200)
        self.add(button)
        self.show_all()

    def mostrar_janela(self):
        if not self.window2:
            self.window2 = Window2()
        # else mostrar janela ?
  • It worked perfectly, as long as I didn’t close the window2 by the x of the window. If you do, when I click again on the button in the first window, window2 opens again, but empty.

  • @user11647 I have no experience with Gtk, so I can’t help you with the details, but the workflow that I would suggest is the following: 1) create the window already in the constructor, but invisible; 2) when clicking the button, show the window; 3) in the default action when closing the window (by x or by other means), choose "hide". You should have options for this in the API, I suggest you do a search.

  • The suggestion is good, but it’s not feasible in a program with many side windows, and from what little I’ve learned so far, Top Level windows cannot be hidden in Gtk, but thanks for the help. He’s already given me a good way!

0

I found a solution until feasible for the issue of allowing only one instance of certain window in Gtk

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from gi.repository import Gtk

class Main(Gtk.Window):
    def __init__(self):
        button = Gtk.Button('Click')
        Gtk.Window.__init__(self, title = 'Main Window')
        button.connect('clicked', self.run_window2)
        self.connect('delete-event', Gtk.main_quit)
        self.set_default_size(300, 200)
        self.add(button)
        self.show_all()

    def run_window2(self, widget):
        try:
            #Chama a janela para frente, se a janela ainda não existe,
            #ocorre um AttributeError, passando então para o except e assim criando a janela. 
            self.window2.present()
        except:
            self.window2 = Window2()

class Window2(Gtk.Window):
    def __init__(self):
        button = Gtk.Button('Exit')
        Gtk.Window.__init__(self, title = 'Window2')
        button.connect('clicked', Gtk.main_quit)
        self.set_default_size(300, 200)
        self.add(button)
        self.show_all()


if __name__ == '__main__':
    Main()
    Gtk.main()

0

Without wanting to belittle the other answers and although they are correct and solve the specific case, maybe in an even better way, also without getting into merits if Singleton is a good design pattern or not my suggestion is for other cases in general.

How to allow only one instance of a given class?

In other words:

How to create a python Singleton?

Using metaclasses:

class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

class Window(object):
    __metaclass__ = Singleton

Or in Python 3

class Window(metaclass=Singleton):
    pass

And finally if you want __init__ be called every time the class is called add:

    else:
        cls._instances[cls].__init__(*args, **kwargs)

source: shamelessly inspired by https://stackoverflow.com/questions/6760685/creating-a-singleton-in-python

  • I don’t think metaclass is a good way to create singletons. Just the method __new__ normal class solves well - and you have no metaclass conflict problem.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.