How to resize GenericMessageDialog text?

I love the appearance of the GenericMessageDialog, but have
encountered the
following problems when attempting to increase the size of the message
font to
improve readability:

1. I'm getting two overlapping instances of the message text, one of
the original size and one of the size that I want.

2. The larger text is truncated at the right-hand edge of the dialog
box.

Any advice will be greatly appreciated. My code follows.

Phillip

import pdb, wx
import wx.lib.agw.genericmessagedialog as GMD

class MyApp(wx.App):

   def OnInit(self):
      frame= wx.Frame(None, -1, "Hello from wxPython")
      message="Do you like the appearance of this dialog?"

      dialog= GMD.GenericMessageDialog(parent=frame, message=message,
        caption='Testing', style=wx.YES_NO | wx.CANCEL |
wx.ICON_INFORMATION)

      message_font= wx.Font(12, wx.SWISS, wx.NORMAL,
wx.FONTWEIGHT_BOLD)

      text= wx.StaticText(dialog, -1, message)
      text.SetFont(message_font)

      return_code= dialog.ShowModal()
      dialog.Destroy()

      if return_code == wx.ID_YES:
         print("The user pressed 'Yes'.")
         return True

      elif return_code == wx.ID_NO:
         print("The user pressed 'No'.")
         return True

      else:
         print("The user pressed 'Cancel'.")
         return False

      # Close the GUI session:
      self.Destroy()

app= MyApp(0)
app.MainLoop()

I love the appearance of the GenericMessageDialog, but have
encountered the
following problems when attempting to increase the size of the message
font to
improve readability:

1. I'm getting two overlapping instances of the message text, one of
the original size and one of the size that I want.

Because you are creating a new instance of a wx.StaticText widget instead of modifying the one(s) that the dialog creates for itself.

2. The larger text is truncated at the right-hand edge of the dialog
box.

Because the dialog and its sizer don't know anything about the widget you created.

Any advice will be greatly appreciated. My code follows.

Looking at the gmd code you might be able to do what you want if you create a new class derived from GenericMessageDialog and override the CreateTextSizer method.

···

On 1/30/12 11:48 AM, Phillip M. Feldman wrote:

--
Robin Dunn
Software Craftsman

<snip>

Looking at the gmd code you might be able to do what you want if you
create a new class derived from GenericMessageDialog and override the
CreateTextSizer method.

This makes sense. Thanks!

I've started looking at genericmessagedialog.py. It uses the
`CreateTextSizer` method, but does not define it. I infer that
`CreateTextSizer` belongs to genericmessagedialog's parent class,
wx.Dialog. So far, I have not been able to find that code. When I do
a search for "CreateTextSizer", the only hit that I get is on the file
_windows.py. This file contains the following comment: "This file was
created automatically by SWIG 1.3.29.
# Don't modify this file, modify the SWIG interface instead." I have
no idea where to look for the code on which my derived class would be
based.

Hi,

<snip>

Looking at the gmd code you might be able to do what you want if you
create a new class derived from GenericMessageDialog and override the
CreateTextSizer method.

This makes sense. Thanks!

I've started looking at genericmessagedialog.py. It uses the
`CreateTextSizer` method, but does not define it. I infer that
`CreateTextSizer` belongs to genericmessagedialog's parent class,
wx.Dialog. So far, I have not been able to find that code. When I do
a search for "CreateTextSizer", the only hit that I get is on the file
_windows.py. This file contains the following comment: "This file was
created automatically by SWIG 1.3.29.
# Don't modify this file, modify the SWIG interface instead." I have
no idea where to look for the code on which my derived class would be
based.

What Robin meant is for you to subclass GenericMessageDialog and
implement your own CreateTextSizer. Unfortunately there is no
pure-Python implementation of this method, as it is defined at the C++
level in dlgcmn.cpp here:

http://svn.wxwidgets.org/viewvc/wx/wxWidgets/trunk/src/common/dlgcmn.cpp?revision=69458&view=markup

And I won't try to convert that to Python myself unless you have time
on your hands. One thing you may try before diving into the C++ stuff
is to assign the font you created to the dialog itself, and then call
something like:

dialog.GetSizer().Layout()

# AND/OR

dialog.GetSizer().Fit(dialog)

# AND/OR

dialog.Fit()

*Before* calling Show() or ShowModal() on your dialog.

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

···

On 2 February 2012 06:35, Phillip M. Feldman <phillip.m.feldman@gmail.com> wrote:

Hello Andrea,

What Robin meant is for you to subclass GenericMessageDialog and
implement your own CreateTextSizer.

This much I understood, but before I can implement my own
`CreateTextSizer`, I need to have some idea of what it is supposed to
be doing. So far, I have not been able to find this. (I am no wiser
after looking at dlgcmn.cpp).

[an alternative is to] assign the font you created to the dialog itself, and then call something like:

<snip>

What does it mean to assign a font to the dialog?

Phillip

P.S. Thanks for the help!

Hi,

Hello Andrea,

What Robin meant is for you to subclass GenericMessageDialog and
implement your own CreateTextSizer.

This much I understood, but before I can implement my own
`CreateTextSizer`, I need to have some idea of what it is supposed to
be doing. So far, I have not been able to find this. (I am no wiser
after looking at dlgcmn.cpp).

In dialog.h:

// splits text up at newlines and places the lines into a vertical
// wxBoxSizer
wxSizer *CreateTextSizer( const wxString& message );

So basically it takes a string, then splits it into lines based on
whatever length is required then creates a StaticText object for each
one and puts them in a BoxSizer which is then returned.

Cody

···

On Thu, Feb 2, 2012 at 3:13 PM, Phillip M. Feldman <phillip.m.feldman@gmail.com> wrote:

Andrea and Cody-

I've gotten this working. Thanks for the help!!

I have two residual questions:

1. I'm surprised that it takes so much code to create and manage a
dialog box with Yes and No buttons. Is my code unnecessarily verbose,
or is this typical for wx?

2. When the program finishes, instead of shutting down nicely, Python
crashes, which is not very elegant. I suspect that I'm doing
something wrong.

Any pointers will be appreciated.

Phillip

--Start of yes_no_demo.py--
# This Python script demonstrates how wxPython can be used to display
a dialog
# box that presents the user with a yes-or-no choice.

import MyMessageDialog, wx
import wx.lib.agw.genericmessagedialog as GMD

# Store `GenericMessageDialog` or `MyMessageDialog` in
`MessageDialog`:
# MessageDialog= GMD.GenericMessageDialog
MessageDialog= MyMessageDialog.MyMessageDialog

class MyApp(wx.App):

   def OnInit(self):
       frame= wx.Frame(None, -1, "Yes_no_demo")
       # frame.Show(True)
       self.SetTopWindow(frame)
       return_code= self.get_yes_or_no(
         message="Do you want to play 'Guess a number'? ")
       return True

   def get_yes_or_no(self, **kwargs):

      if 'prompt' in kwargs:
         kwargs['message']= kwargs['prompt']
         del kwargs['prompt']
      elif not 'message' in kwargs:
         kwargs['message']= 'Make a choice: '

      if not 'caption' in kwargs:
         kwargs['caption']= 'Waiting for user input'

      # The 'message_font' keyword is accepted by `MyMessageDialog`,
but not by
      # `GenericMessageDialog`:
      if MessageDialog == MyMessageDialog.MyMessageDialog:
         if not 'message_font' in kwargs:
            kwargs['message_font']= 13
      else:
         if 'message_font' in kwargs:
            del kwargs['message_font']

      dialog= MessageDialog(parent=None,
        style=wx.YES_NO | wx.CANCEL | wx.ICON_INFORMATION, **kwargs)

      return_code= dialog.ShowModal()
      dialog.Destroy()

      if return_code == wx.ID_YES:
         print("You clicked on 'Yes'.")

      elif return_code == wx.ID_NO:
         print("You clicked on 'No'.")

      # Close the GUI session:
      self.Destroy()

if __name__ == '__main__':
   app= MyApp(0)
   app.MainLoop()
--End of yes_no_demo.py--

--Start of MyMessageDialog.py--
import wx
import wx.lib.agw.genericmessagedialog as GMD

class MyMessageDialog(GMD.GenericMessageDialog):

   # Constructor:
   def __init__(self, parent=None, **kwargs):

      # Set 'message_font' attribute of the class. If the `kwargs`
dictionary
      # contains the 'message_font' key, we must remove this key
before the
      # dictionary is passed to the super class constructor.
      if 'message_font' in kwargs:
         self.message_font= kwargs['message_font']
         del kwargs['message_font']
      else:
         self.message_font= 12

      # If `self.message_font` is an int, replace it by instance of
`wx.Font`:
      if isinstance(self.message_font, int):
         self.message_font= wx.Font(self.message_font,
           wx.SWISS, wx.NORMAL, wx.FONTWEIGHT_BOLD)

      self.parent= parent
      self.frame= wx.Frame(parent=self.parent)
      self.panel= wx.Panel(parent=self.frame)

      # Invoke constructor of the super class:
      super(MyMessageDialog, self).__init__(parent=self.frame,
**kwargs)

   def CreateTextSizer(self, message):
      txt= wx.StaticText(parent=self, id=-1, label=message)
      txt.SetFont(self.message_font)
      sizer= wx.BoxSizer()
      sizer.Add(txt)
      return sizer
--End of MyMessageDialog.py--

I have attached a really simple example of the Generic Message Dialog. But to answer your question, it depends. If you need a lot of specialized dialogs or if you want a lot of whiz-bang stuff, then yes, wx can get pretty verbose. Once you get the hang of wx though, you can reduce your line count considerably. It just takes practice.

generic-msg-dlg.py (914 Bytes)

···

Mike Driscoll
www.mousevspython.com

Phillip M. Feldman wrote:

1. I'm surprised that it takes so much code to create and manage a
dialog box with Yes and No buttons. Is my code unnecessarily verbose,
or is this typical for wx?

Your dialog is only about a dozen lines of code, and part of that is the
parameter handling.

Really, you only appreciate how much wx is doing for you if you have
previously worked directly with the API. Your same example, written in
C or C++, would have eight or ten times the code.

2. When the program finishes, instead of shutting down nicely, Python
crashes, which is not very elegant. I suspect that I'm doing
something wrong.

Yes, you are, but the problem is subtle and unlikely to occur in a real
application. The issue here is that you are doing ALL of your
processing in the wx.App.OnInit handler, all the way from the creation
of the top level window to the creation of your modal dialog to the
call to App.Destroy. All of that processing happens before the
application's message loop has even started.

I don't know what wx.App.Destroy does. Destroy is usually called on a
window, not on an application. The application ends when the last
window is closed, but you aren't closing any windows here.

In this particular example, remove the call to self.Destroy() and return
False from OnInit. That will eliminate the crash. In a real-world
program, this won't be an issue.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Nice example.

To reduce the line count by one more, how about this?

with GMD.GenericMessageDialog(self, message="This is a test",
                              caption="Testing",
                              agwStyle=wx.ICON_INFORMATION|wx.OK) as dlg:
    dlg.ShowModal()

Then there's no need for the "Destroy()".

WH

···

On Mon, 06 Feb 2012 08:44:02 -0800, Mike Driscoll wrote:

I have attached a really simple example of the Generic Message Dialog.
But to answer your question, it depends. If you need a lot of
specialized dialogs or if you want a lot of whiz-bang stuff, then yes,
wx can get pretty verbose. Once you get the hang of wx though, you can
reduce your line count considerably. It just takes practice.

It is a dialog which should be destroyed.

Add the following to the MyFrame class:

         self.Bind(wx.EVT_CLOSE, self.OnClose)

     def OnClose(self, event):
         print wx.GetTopLevelWindows()
         event.Skip()

Then run the code with Destroy and without.

I just about always do:

try:
     dlg.ShowModal()
     ....
finally:
     dlg.Destroy()

To ensure that even if an exception throws in the dialog it gets destroyed, but agreed for a GMD this is overkill.

Werner

···

On 06/02/2012 21:25, Walter Hurry wrote:

On Mon, 06 Feb 2012 08:44:02 -0800, Mike Driscoll wrote:

I have attached a really simple example of the Generic Message Dialog.
But to answer your question, it depends. If you need a lot of
specialized dialogs or if you want a lot of whiz-bang stuff, then yes,
wx can get pretty verbose. Once you get the hang of wx though, you can
reduce your line count considerably. It just takes practice.

Nice example.

To reduce the line count by one more, how about this?

with GMD.GenericMessageDialog(self, message="This is a test",
                               caption="Testing",
                               agwStyle=wx.ICON_INFORMATION|wx.OK) as dlg:
     dlg.ShowModal()

Then there's no need for the "Destroy()".

<snip>

Exactly the same result, provided that the "with" is used, as per my
previous post.

···

On Tue, 07 Feb 2012 09:35:21 +0100, werner wrote:

On 06/02/2012 21:25, Walter Hurry wrote:

On Mon, 06 Feb 2012 08:44:02 -0800, Mike Driscoll wrote:

I have attached a really simple example of the Generic Message Dialog.
But to answer your question, it depends. If you need a lot of
specialized dialogs or if you want a lot of whiz-bang stuff, then yes,
wx can get pretty verbose. Once you get the hang of wx though, you can
reduce your line count considerably. It just takes practice.

Nice example.

To reduce the line count by one more, how about this?

with GMD.GenericMessageDialog(self, message="This is a test",
                               caption="Testing",
                               agwStyle=wx.ICON_INFORMATION|wx.OK) as
                               dlg:
     dlg.ShowModal()

Then there's no need for the "Destroy()".

It is a dialog which should be destroyed.

Add the following to the MyFrame class:

         self.Bind(wx.EVT_CLOSE, self.OnClose)

     def OnClose(self, event):
         print wx.GetTopLevelWindows() event.Skip()

Then run the code with Destroy and without.

wxPython's wx.Dialog adds the magic methods that enable it to be used as a context manager with the Python "with" statement. Destroy is then called automatically upon exit from the context.

         def __enter__(self):
             return self
         def __exit__(self, exc_type, exc_val, exc_tb):
             self.Destroy()

···

On 2/7/12 12:35 AM, werner wrote:

On 06/02/2012 21:25, Walter Hurry wrote:

On Mon, 06 Feb 2012 08:44:02 -0800, Mike Driscoll wrote:

I have attached a really simple example of the Generic Message Dialog.
But to answer your question, it depends. If you need a lot of
specialized dialogs or if you want a lot of whiz-bang stuff, then yes,
wx can get pretty verbose. Once you get the hang of wx though, you can
reduce your line count considerably. It just takes practice.

Nice example.

To reduce the line count by one more, how about this?

with GMD.GenericMessageDialog(self, message="This is a test",
caption="Testing",
agwStyle=wx.ICON_INFORMATION|wx.OK) as dlg:
dlg.ShowModal()

Then there's no need for the "Destroy()".

It is a dialog which should be destroyed.

--
Robin Dunn
Software Craftsman

Hi Walter,

...

<snip> Exactly the same result, provided that the "with" is used, as per my previous post.

Oops, didn't see the "with".

Werner

···

On 07/02/2012 17:15, Walter Hurry wrote: