I'd like to determine the respective associated pane for the events
triggered on the caption bars; is something like this possible?
I managed to make a popup window with a static text, which copies the
full caption text and displayes it over the (reduced) caption, but
it's rather difficult to call this popup properly (currently I'm
trying the EVT_ENTER_WINDOW of the pane, but this obviously doesn't
work on the children widgets of the panes).
Do I have to bind all single widgets individually, or is there maybe a
more elegant way (or even a better solution to the whole problem with
shortened captions - e.g. setting simple tooltips somehow ...)?
any suggestions are much appreciated,
thanks in advance
Vlasta
On Tue, Feb 24, 2009 at 12:20 AM, Vlastimil Brom wrote:
> Hi I am just trying to solve another task in the aui layout of my app
> and would like to to ask about the status of caption bars in
> AuiManager.
> Currently, some longer caption texts aren't fully visible and I'd like
> to show them in some way.
> Unfortunately I couldn't figure out, whether the caption bars are
> somehow programatically accessible (besides setting text or style).
> Using the widget inspection tool it seems, that they are part of the
> main AUI frame, as its events are triggerd on them (EVT_MOTION and
> EVT_ENTER_WINDOW - but a bit strangely not EVT_LEAVE_WINDOW).
If you can wait few days, I am going to release 2 different (but
almost equivalent) versions of wxAUI written in pure Python, which do
the same things as wxAUI and many others that wxAUI doesn't do. I will
put them in wxPython SVN for the wxPython community to try and
experiment with them: the obvious advantages wrt wxAUI are twofold:
- It's Python, so you/we can tinker them as much as we like to modify
them to suit our needs;
- Patches will be implemented at a faster pace than the current C++
version of wxAUI.
Andrea.
"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/
When the pane is floating then it is embedded in a AuiFloatingFrame
which is a class derived from wx.MiniFrame. It's the mini frame that
draws the caption, moves the frame when dragged, etc. and since the
caption is not considered part of the client area of the frame[*] then
wx doesn't give access to catching events from it, although it can
probably be done at least partially with native code and non-client events.
[*] that may vary across platforms as the miniframe doesn't have a
native implementation everywhere, so it may be simulated with plain wx code.
>
> I managed to make a popup window with a static text, which copies the
> full caption text and displayes it over the (reduced) caption, but
> it's rather difficult to call this popup properly (currently I'm
> trying the EVT_ENTER_WINDOW of the pane, but this obviously doesn't
> work on the children widgets of the panes).
> Do I have to bind all single widgets individually, or is there maybe a
> more elegant way (or even a better solution to the whole problem with
> shortened captions - e.g. setting simple tooltips somehow ...)?
A tooltip would be nice, but I don't think that frame windows will
display them. Without being able to get mouse events in the caption
area I can only think of two possible approaches, and neither of them is
very good IMO.
1. Use an EVT_IDLE handler to (re)set a timer. Doing it from a EVT_IDLE
handler will cause it to be restarted every time there is any events in
your app. When the timer does expire use wx.GetMousePosition to see if
the cursor is currently within the bounds of the active AuiFloatingFrame
window, and near the top. If so then use a wx.TipWindow to display a
tooltip-like window with your text.
2. You can use a timer to animate the mini frame's title text such that
it appears to slide back and forth.
--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!
Hi Robin,
thanks for your suggestions! I'm actually interested in both docked as
well as floating panes (the former are more frequent in this layout).
Unfortunately, I am not able to determine the rectangle of the pane
caption (otherwise the EVT_ENTER_WINDOW event of the aui-frame would
be just fine, as it gets triggered mostly on the pane captions) - the
only way I could think of was to maintain the list of rectangles for
all panes and somehow calculate the position of the caption bar (given
the pane width and caption height -
_mgr.GetArtProvider().GetMetric(wx.aui.AUI_DOCKART_CAPTION_SIZE), this
list would have to be updated with the each rendering of the aui
manager.
Sofar I haven't tried this approach, as it doesn't seem optimal to me;
currently I have all panels and their child widgets bound to the
EVT_ENTER_WINDOW - with a function showing the complete caption via a
PopupWindow - hence it shows more frequently than usual, and not under
the mouse on caption bar, but it isn't realy disturbing.
I'll eventually check the alternatives.
Thanks again,
Vlasta
Hi Andrea,
thank you very much for your effort - and first, I'd like to join the
gratulations you already got :-)
I guess, the full aui implementation in Python would be nice (I am not
hoping, I'd be able to effectively modify the code for something that
complex, but (at least for me) it would surely be more comprehensible,
what's going on ...).
If I may draw your attention to one specific shortcomming in aui, it
would be the issue with destructive resizing of docked panes (unless
it had been fixed somewhere in the original codebase):
http://trac.wxwidgets.org/ticket/4599
http://lists.wxwidgets.org/pipermail/wxpython-users/2008-January/071847.html
currently I am using a variation on the code proposed in the list
above, but it would be nice, if it were fixed in the library.
And, again, many thanks for all your contributions to wxpython!
regards,
Vlasta
Hi again,
I just wanted to post the results of further trials on showing the aui
pane captions and ask for opinions or suggestions.
It turned out, that using EVT_ENTER_WINDOW of the AUI frame isn't all
that complicated (or my code is messy enough for this to make a
difference ...:-)
It is necessary to maintain a list of rectangles of all aui panes -
and to update it on changing the layout.
The tricky part is maybe to infer the coordinates of the caption bar
based on the rectangles of the respective panes.
Furthermore it turned out, that EVT_ENTER_WINDOW is also generated
after discarding the popup window, previously placed over the caption.
I couldn't find a way to prevent it other than using a guarding
variable and resetting it with an arbitrary interval wx.CallLater.
In this version the popups behave more naturaly; however, they are
also called on shorter captions, where they aren't needed, besides
this, while moving from one caption to the neighbour one, no event is
generated as the mouse actualy doesn't enter any new widget; I am not
sure, whether it is important enough to use EVT_MOTION instead. This
way also doesn't work on floating frames, but there are native
tooltips there anyway.
The sample code is attached, I'd really appreciate comments or
suggestions of better approaches. (I also apologise for the coding
style :-), the main objective is to test the usability ...).
Thanks in advance
Vlasta
#### sample code - wx-aui-popup-caption-sample.py- also attached ###########
#! Python
# -*- coding: utf-8 -*-
import wx
import wx.aui
class PopupInfoText(wx.PopupWindow): # PopupTransientWindow
"""
wx.PopupWindow for displaying context help/information
"""
def __init__(self, parent, *args, **kwargs):
wx.PopupWindow.__init__(self, parent, *args, **kwargs)
self.info_text = wx.StaticText(self, -1, u"", pos=(2, 2))
self.discard_timer = wx.CallLater(2000, self.hide_popup)
self.discard_timer.Stop() # stop in order not to call
hide_popup before actual using
self.info_text.Bind(wx.EVT_LEFT_UP, self.hide_popup)
self.should_hide = False # to prevent repeated popups on
EVT_ENTER_WINDOW - popup > frame
def show_popup_info(self, info_txt="", pos=(0,0), display_duration_ms=2000):
"""
Shows the popup with given text on given coordinates; check
for self.should_hide to prevent circular popups.
"""
if self.should_hide:
self.should_hide = False
return False
self.should_hide = False
self.Show(False)
self.info_text.SetLabel(info_txt)
txt_size = self.info_text.GetBestSize()
self.SetSize((txt_size[0]+5, txt_size[1]+4))
coord_x, coord_y = pos
if (self.GetSize()[0] + coord_x) > wx.GetDisplaySize()[0]: #
popup (partly) outside the screen
coord_x = wx.GetDisplaySize()[0] - self.GetSize()[0] #
align a longer popup with right margin
if coord_x < 0:
coord_x = 0 # align with a left margin if the popup is
longer than the screen width # wrapping not implemented
self.SetPosition((coord_x, coord_y))
self.Show(True)
self.discard_timer.Restart(display_duration_ms) # restart for
a new timeout interval after resetting/updating
def hide_popup(self, evt=None):
"""
Hides popup after a timeout or by clicking on it (moving the panes etc).
"""
self.Show(False)
self.should_hide = True
self.discard_timer.Stop() # stopping for hiding the popup via mouse
wx.CallLater(200, self.unset_should_hide) # approx timeout??;
prevent circular calls, reset for next noprmal pane
def unset_should_hide(self, evt=None):
"""
Unset the hiding parameter for other than immediate (not
wanted) calls of show_popup_info.
"""
self.should_hide = False
class AuiFrame(wx.Frame):
"""
sample frame - aui manager with longer pane captions and
associated popup hints
"""
def __init__(self, parent, id=-1, title='wx.aui - popup captions',
pos=(10,10), size=(-1, -1), style=wx.DEFAULT_FRAME_STYLE):
wx.Frame.__init__(self, parent, id, title, pos, size, style)
self._mgr = wx.aui.AuiManager(self)
for (pane_nr, pane_pos) in enumerate((wx.BOTTOM, wx.LEFT,
wx.RIGHT, wx.TOP)*4):
self._mgr.AddPane(self.MakeTextCtrl(str(pane_nr)),
pane_pos, 'some rather longer text of the pane caption nr.
'+str(pane_nr))
self._mgr.AddPane(self.MakeTextCtrl(),wx.aui.AuiPaneInfo().Center().CloseButton(False).CaptionVisible(False).Name("emptyPanel"))
self.pop_inf = PopupInfoText(self)
self.panes_rectangles = []
self.Bind(wx.EVT_ENTER_WINDOW, self.display_caption_popup)
self.Bind(wx.aui.EVT_AUI_RENDER, self.onRender)
self._mgr.Update()
def onRender(self,evt):
"""
Collect pane rectangles for checking the mouse on pane
captions display_caption_popup; updated on lazout changes.
"""
self.panes_rectangles = [(pane_info,
pane_info.window.GetRect()) for pane_info in self._mgr.GetAllPanes()]
evt.Skip()
def MakeTextCtrl(self, txt='sample text'):
return wx.TextCtrl(self, -1, txt, style=wx.TE_MULTILINE)
def display_caption_popup(self, evt):
"""
Determines the pane based on the mouse position; calls the
popup with its caption on the computed coordinates.
"""
x_coord, y_coord = evt.GetX(), evt.GetY()
caption_height =
self._mgr.GetArtProvider().GetMetric(wx.aui.AUI_DOCKART_CAPTION_SIZE)
sash_thickness =
self._mgr.GetArtProvider().GetMetric(wx.aui.AUI_DOCKART_SASH_SIZE)
pane_border_size =
self._mgr.GetArtProvider().GetMetric(wx.aui.AUI_DOCKART_PANE_BORDER_SIZE)
for (pane_info, (x_pos, y_pos, pane_width, pane_height)) in
self.panes_rectangles:
if (x_pos - sash_thickness - 2 * pane_border_size) <=
x_coord <= (x_pos + pane_width + sash_thickness + 2 *
pane_border_size): # mouse in the same "column" as the pane
if y_pos >= y_coord >= (y_pos - caption_height -
sash_thickness - 2 * pane_border_size): # panes on the top - no sash
or border above; interval also ok?
if pane_info.IsShown(): # check visible panes only
(the hidden ones keep the previous positions)
self.pop_inf.show_popup_info(pane_info.caption,
self.ClientToScreen((x_pos, (y_pos - caption_height))))
break
if __name__ == '__main__':
app = wx.App(redirect=False)
frm = AuiFrame(None)
frm.Show()
app.MainLoop()