Question

I'm creating program in python with gtk as gui using glade. In that program, I have several message dialog. It's simple if I just make many message dialog for every case I have. But, is it possible to just make one message dialog and use it for different case with different text? It's simple actually. I just need to change primary text and show it. But, I don't find a way to change primary text here and here.

Below is a sample code:

from gi.repository import Gtk

def clicked1(widget):
    response = dialog1.run()
    if response == Gtk.ResponseType.OK:
        print 'ok'
    else:
        print 'cancel'
        dialog1.destroy()

def clicked2(widget):
    response = dialog2.run()
    if response == Gtk.ResponseType.OK:
        print 'ok'
    else:
        print 'cancel'
        dialog2.destroy()

def clicked3(widget):
    response = dialog3.run()
    if response == Gtk.ResponseType.OK:
        print 'ok'
    else:
        print 'cancel'
        dialog3.destroy()

builder = Gtk.Builder()
builder.add_from_file('gui.glade')
dialog1 = builder.get_object('dialog1')
dialog2 = builder.get_object('dialog2')
dialog3 = builder.get_object('dialog3')
builder.get_object('button1').connect('clicked', clicked1)
builder.get_object('button2').connect('clicked', clicked2)
builder.get_object('button3').connect('clicked', clicked3)
builder.get_object('window1').show_all()
Gtk.main()

I want to change it to be something like this

from gi.repository import Gtk

def clicked1(widget):
    **dialog.set_text(1)**
    response = dialog.run()
    if response == Gtk.ResponseType.OK:
        print 'ok'
    else:
        print 'cancel'
        dialog.destroy()

def clicked2(widget):
    **dialog.set_text(2)**
    response = dialog.run()
    if response == Gtk.ResponseType.OK:
        print 'ok'
    else:
        print 'cancel'
        dialog.destroy()

def clicked3(widget):
    **dialog.set_text(3)**
    response = dialog.run()
    if response == Gtk.ResponseType.OK:
        print 'ok'
    else:
        print 'cancel'
        dialog.destroy()

builder = Gtk.Builder()
builder.add_from_file('gui.glade')
**dialog = builder.get_object('dialog')**
builder.get_object('button1').connect('clicked', clicked1)
builder.get_object('button2').connect('clicked', clicked2)
builder.get_object('button3').connect('clicked', clicked3)
builder.get_object('window1').show_all()
Gtk.main()
Was it helpful?

Solution 2

It seems that there is no directly way to refresh text in gtk_message_dialog after initialization, but because a message dialog is combination of boxes, labels, images and buttons, so this is an ugly way to modify/refresh primary/secondary text in a message dialog,

labels = dialog_info.get_children()[0].get_children()[0].get_children()[1].get_children()

Full source code of this demo is here:

#!/usr/bin/env python3

from gi.repository import Gtk

class Handler:
    def __init__(self, builder):
        self.builder = builder
        self.window = builder.get_object('window1')

    def run(self):
        self.window.show_all()
        Gtk.main()

    def on_app_exit(self, widget, event=None):
        Gtk.main_quit()

    def on_button_show_clicked(self, btn):
        dialog_info = self.builder.get_object('messagedialog_info')
        entry = self.builder.get_object('entry1')
        labels = dialog_info.get_children()[0].get_children()[0].get_children()[1].get_children()
        print(labels)
        # labels[0] is the primary label.
        # labels[1] is the seconary label.
        labels[0].set_text(entry.get_text())

        response = dialog_info.run()
        print('response: ', response)
        dialog_info.hide()


def main():
    builder = Gtk.Builder()
    builder.add_from_file('example.glade')
    handler = Handler(builder)
    builder.connect_signals(handler)
    handler.run()

if __name__ == '__main__':
    main()

and the glade file, 'example.glade':

<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <!-- interface-requires gtk+ 3.0 -->
  <object class="GtkMessageDialog" id="messagedialog_info">
    <property name="can_focus">False</property>
    <property name="border_width">5</property>
    <property name="type_hint">dialog</property>
    <property name="skip_taskbar_hint">True</property>
    <property name="buttons">close</property>
    <property name="text" translatable="yes">hello text</property>
    <property name="secondary_text" translatable="yes">hello secondary text.</property>
    <child internal-child="vbox">
      <object class="GtkBox" id="messagedialog-vbox">
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <property name="spacing">2</property>
        <child internal-child="action_area">
          <object class="GtkButtonBox" id="messagedialog-action_area">
            <property name="can_focus">False</property>
            <property name="layout_style">end</property>
            <child>
              <placeholder/>
            </child>
            <child>
              <placeholder/>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="pack_type">end</property>
            <property name="position">0</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
  <object class="GtkWindow" id="window1">
    <property name="can_focus">False</property>
    <property name="border_width">5</property>
    <signal name="delete-event" handler="on_app_exit" swapped="no"/>
    <child>
      <object class="GtkBox" id="box1">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="valign">center</property>
        <property name="spacing">5</property>
        <child>
          <object class="GtkEntry" id="entry1">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="invisible_char">●</property>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkButton" id="button_show">
            <property name="label" translatable="yes">_Show</property>
            <property name="use_action_appearance">False</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <property name="use_action_appearance">False</property>
            <property name="use_underline">True</property>
            <signal name="clicked" handler="on_button_show_clicked" swapped="no"/>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

OTHER TIPS

Maybe a little bit too late, but I was looking for the same thing and I could get a simple yet efficient way of changing primary and secondary texts without calling any GtkMessageDialog pre-built method.

I was just trying to understand how it was not possible to have something easier to change these texts without calling the pre-built methods "set_markup" and "format_secondary_text". Even if "format_secondary_text" works like a charm and de-facto change the second text perfectly, "set_markup" changes the primary text, but not as it should because it does not get as title in presence of the second text, I expected it to become bold, but it is waiting for some PANGO markup, otherwise it is only a simple non-bold text.

Then I opened Idle just to take a look at all methods, properties and so on that might be available for GtkMessageDialog and I found something, as I paste it below:

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
builder = Gtk.Builder()
#any Glade file with at least 1 GtkMessageDialog
builder.add_from_file("myFile.glade") 
#The ID of GtkMessageDialog in Glade
myDialog = builder.get_object("GtkMessageDialog1")

#Below I change primary and secondary texts before running the Dialog.
myDialog.set_property("text","Hello World")
myDialog.set_property("secondary_text","Here I go again.")

myDialog.run()
myDialog.hide()

Just pay attention as I wrote using Python 2.7, but the principle must be the same as with Python 3.x.

Alternatively, we can just write some wrapping functions of gtk_message_dialog, and here is a simple example:

def info(text, text2=None):
    dialog = Gtk.MessageDialog(None,
            Gtk.DialogFlags.MODAL,
            Gtk.MessageType.INFO,
            Gtk.ButtonsType.OK,
            text)
    if text2 != None:
        dialog.format_secondary_text(text2)
    response = dialog.run()
    dialog.destroy()

The problems is that if no parent window is spesified in the message dialog, it will show in the center of screen, rather than center of program. To solve this problem, we can put info() function in the class and set its parent window parameter.

Other types of message like warning, question and error can do the same way.

And a small demo:

#!/usr/bin/env python3

from gi.repository import Gtk

def info(text, text2=None):
    dialog = Gtk.MessageDialog(None,
            Gtk.DialogFlags.MODAL,
            Gtk.MessageType.INFO,
            Gtk.ButtonsType.OK,
            text)
    if text2 != None:
        dialog.format_secondary_text(text2)
    response = dialog.run()
    dialog.destroy()

def error(text, text2=None):
    '''
    TODO
    '''
    pass

def main():
    win = Gtk.Window()
    win.connect('delete-event', Gtk.main_quit)
    win.show_all()
    info('hello')
    info('hello, primary text', 'hello secondary text')

    Gtk.main()

if __name__ == '__main__':
    main()

Widget structure of a message dialog is like this: enter image description here

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top