Problem with cursor handling

Hello,

my problem is that when I enter a panel of a resizable frame the
cursor sometimes does not show the default arrow state, but the state
it has while hovering over the frame border. If I run into this
situation depends strongly on the speed I use to enter my panel.

My code:

import wx
import win32com.client.gencache

class ViewerPanel(wx.Panel):
    def __init__(self, *args, **kwargs):
        super(ViewerPanel, self).__init__(*args, **kwargs)

        self.viewer = None
        sizer = wx.BoxSizer(wx.VERTICAL)
        control =
win32com.client.gencache.EnsureModule('{DD3BD3FD-8B58-406F-
AA17-714C852F07AD}', 0x0, 1, 0)
        ActiveXWrapper = MakeActiveXClass(control.CADdyViewer)

        self.SetWindowStyle(wx.WANTS_CHARS)

        sizer.Add(self.viewer, 1, wx.EXPAND)

        self.SetSizer(sizer)
        self.SetAutoLayout(True)

        wx.EVT_WINDOW_DESTROY(self, self.OnDestroy)

        self.Bind(wx.EVT_IDLE, self.OnIdle)

    def OnDestroy(self, evt):
        if self.viewer:
            self.viewer.Cleanup()
            self.viewer = None
        evt.Skip()

    def OnIdle(self, event):
        if self.viewer:
            self.viewer.OnIdle()
        event.Skip()
def main():
    app = wx.App(False)
    frm = wx.Frame(None, title="ViewerPanel test window")

    panel = ViewerPanel(frm)
    panel.viewer.Load(r'dinopet.3ds', False, True)
    panel.viewer.SetHeadLightState(True)

    frm.Show()
    app.MainLoop()

if __name__ == '__main__':
    main()

As you can see my panel is actually an acitveX wrapped window, which I
have written myself. Basically it is defined by

class CCADdyViewerCtrl : public COleControl
{
    DECLARE_DYNCREATE(CCADdyViewerCtrl)

    // Constructor
public:
    CCADdyViewerCtrl();

    // Overrides
public:
    virtual void OnDraw(CDC* pdc, const CRect& rcBounds, const CRect&
rcInvalid);
    virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
    virtual void DoPropExchange(CPropExchange* pPX);
    virtual void OnResetState();
    virtual DWORD GetControlFlags();

    // Implementation
protected:
    ~CCADdyViewerCtrl();

    DECLARE_OLECREATE_EX(CCADdyViewerCtrl) // Class factory and
guid
    DECLARE_OLETYPELIB(CCADdyViewerCtrl) // GetTypeInfo
    DECLARE_PROPPAGEIDS(CCADdyViewerCtrl) // Property page IDs
    DECLARE_OLECTLTYPE(CCADdyViewerCtrl) // Type name and misc
status

    //{{AFX_MSG(CCADdyViewerCtrl)
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    afx_msg void OnDestroy();
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()

    //{{AFX_DISPATCH(CCADdyViewerCtrl)
    afx_msg BOOL Load (LPCTSTR name,
BOOL load_into_current, BOOL deactivate_light);
    afx_msg void SetHeadLightState (BOOL flag);
    ...
    //}}AFX_DISPATCH
    DECLARE_DISPATCH_MAP()
    DECLARE_EVENT_MAP()

private:
    // details...
};

with these implementation details

static const DWORD BASED_CODE _dwCADdyViewerOleMisc =
OLEMISC_ACTIVATEWHENVISIBLE |
OLEMISC_IGNOREACTIVATEWHENVISIBLE |
OLEMISC_SETCLIENTSITEFIRST |
OLEMISC_INSIDEOUT |
OLEMISC_CANTLINKINSIDE |
OLEMISC_RECOMPOSEONRESIZE;

IMPLEMENT_OLECTLTYPE(CCADdyViewerCtrl, IDS_CADDYVIEWER,
_dwCADdyViewerOleMisc)

BOOL CCADdyViewerCtrl::PreCreateWindow(CREATESTRUCT& cs)
{
    // these styles are required by OpenGL
    cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;

    if (cs.dwExStyle & WS_EX_NOPARENTNOTIFY)
        cs.dwExStyle -= WS_EX_NOPARENTNOTIFY;

    // these styles are meant for a use of this class in a MDI
application
    cs.lpszClass = AfxRegisterWndClass(CS_OWNDC | CS_HREDRAW |
CS_VREDRAW);
    return COleControl::PreCreateWindow(cs);
}

int CCADdyViewerCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    lpCreateStruct->style |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;

    if (COleControl::OnCreate(lpCreateStruct) == -1)
        return -1;

    return 0;
}

Does anyone has an idea what could be the reason for the failing
cursor update in this scenario? I have tried to goole some information
but could not find anything valuable.

How is the cursor switching handled at all when entering a window?
Should I assume the problem in the wx related code or in my MFC code?

Everything else in my activeX control panel is perfectly working. The
control wrappes an OpenGL viewer, but I have tried to abandon all that
code with the very same result with respect to the cursor.

A last comment, I'm working with wxPython 2.9.1.1 on Python 2.7.1.

Any help is appreciated.

Best,
Johannes

I did forget one important line of code namly

self.viewer = ActiveXWrapper( self, -1, style=wx.SUNKEN_BORDER)

···

On Jul 21, 1:48 pm, Johannes <JBru...@DataSolid.de> wrote:

Hello,

my problem is that when I enter a panel of a resizable frame the
cursor sometimes does not show the default arrow state, but the state
it has while hovering over the frame border. If I run into this
situation depends strongly on the speed I use to enter my panel.

My code:

import wx
import win32com.client.gencache

class ViewerPanel(wx.Panel):
def __init__(self, *args, **kwargs):
super(ViewerPanel, self).__init__(*args, **kwargs)

    self\.viewer = None
    sizer = wx\.BoxSizer\(wx\.VERTICAL\)
    control =

win32com.client.gencache.EnsureModule('{DD3BD3FD-8B58-406F-
AA17-714C852F07AD}', 0x0, 1, 0)
ActiveXWrapper = MakeActiveXClass(control.CADdyViewer)

    self\.SetWindowStyle\(wx\.WANTS\_CHARS\)

    sizer\.Add\(self\.viewer, 1, wx\.EXPAND\)

    self\.SetSizer\(sizer\)
    self\.SetAutoLayout\(True\)

    wx\.EVT\_WINDOW\_DESTROY\(self, self\.OnDestroy\)

    self\.Bind\(wx\.EVT\_IDLE, self\.OnIdle\)

def OnDestroy\(self, evt\):
    if self\.viewer:
        self\.viewer\.Cleanup\(\)
        self\.viewer = None
    evt\.Skip\(\)

def OnIdle\(self, event\):
    if self\.viewer:
        self\.viewer\.OnIdle\(\)
    event\.Skip\(\)

def main():
app = wx.App(False)
frm = wx.Frame(None, title="ViewerPanel test window")

panel = ViewerPanel\(frm\)
panel\.viewer\.Load\(r&#39;dinopet\.3ds&#39;, False, True\)
panel\.viewer\.SetHeadLightState\(True\)

frm\.Show\(\)
app\.MainLoop\(\)

if __name__ == '__main__':
main()

As you can see my panel is actually an acitveX wrapped window, which I
have written myself. Basically it is defined by

class CCADdyViewerCtrl : public COleControl
{
DECLARE_DYNCREATE(CCADdyViewerCtrl)

// Constructor

public:
CCADdyViewerCtrl();

// Overrides

public:
virtual void OnDraw(CDC* pdc, const CRect& rcBounds, const CRect&
rcInvalid);
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
virtual void DoPropExchange(CPropExchange* pPX);
virtual void OnResetState();
virtual DWORD GetControlFlags();

// Implementation

protected:
~CCADdyViewerCtrl();

DECLARE\_OLECREATE\_EX\(CCADdyViewerCtrl\)    // Class factory and

guid
DECLARE_OLETYPELIB(CCADdyViewerCtrl) // GetTypeInfo
DECLARE_PROPPAGEIDS(CCADdyViewerCtrl) // Property page IDs
DECLARE_OLECTLTYPE(CCADdyViewerCtrl) // Type name and misc
status

//\{\{AFX\_MSG\(CCADdyViewerCtrl\)
afx\_msg int OnCreate\(LPCREATESTRUCT lpCreateStruct\);
afx\_msg void OnDestroy\(\);
//\}\}AFX\_MSG
DECLARE\_MESSAGE\_MAP\(\)

//\{\{AFX\_DISPATCH\(CCADdyViewerCtrl\)
afx\_msg BOOL        Load                            \(LPCTSTR name,

BOOL load_into_current, BOOL deactivate_light);
afx_msg void SetHeadLightState (BOOL flag);
...
//}}AFX_DISPATCH
DECLARE_DISPATCH_MAP()
DECLARE_EVENT_MAP()

private:
// details...

};

with these implementation details

static const DWORD BASED_CODE _dwCADdyViewerOleMisc =
OLEMISC_ACTIVATEWHENVISIBLE |
OLEMISC_IGNOREACTIVATEWHENVISIBLE |
OLEMISC_SETCLIENTSITEFIRST |
OLEMISC_INSIDEOUT |
OLEMISC_CANTLINKINSIDE |
OLEMISC_RECOMPOSEONRESIZE;

IMPLEMENT_OLECTLTYPE(CCADdyViewerCtrl, IDS_CADDYVIEWER,
_dwCADdyViewerOleMisc)

BOOL CCADdyViewerCtrl::PreCreateWindow(CREATESTRUCT& cs)
{
// these styles are required by OpenGL
cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;

if \(cs\.dwExStyle &amp; WS\_EX\_NOPARENTNOTIFY\)
    cs\.dwExStyle \-= WS\_EX\_NOPARENTNOTIFY;

// these styles are meant for a use of this class in a MDI

application
cs.lpszClass = AfxRegisterWndClass(CS_OWNDC | CS_HREDRAW |
CS_VREDRAW);
return COleControl::PreCreateWindow(cs);

}

int CCADdyViewerCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
lpCreateStruct->style |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;

if \(COleControl::OnCreate\(lpCreateStruct\) == \-1\)
    return \-1;

return 0;

}

Does anyone has an idea what could be the reason for the failing
cursor update in this scenario? I have tried to goole some information
but could not find anything valuable.

How is the cursor switching handled at all when entering a window?
Should I assume the problem in the wx related code or in my MFC code?

Everything else in my activeX control panel is perfectly working. The
control wrappes an OpenGL viewer, but I have tried to abandon all that
code with the very same result with respect to the cursor.

A last comment, I'm working with wxPython 2.9.1.1 on Python 2.7.1.

Any help is appreciated.

Best,
Johannes

Hello,

my problem is that when I enter a panel of a resizable frame the
cursor sometimes does not show the default arrow state, but the state
it has while hovering over the frame border. If I run into this
situation depends strongly on the speed I use to enter my panel.

[...]

Does anyone has an idea what could be the reason for the failing
cursor update in this scenario? I have tried to goole some information
but could not find anything valuable.

How is the cursor switching handled at all when entering a window?
Should I assume the problem in the wx related code or in my MFC code?

wx responds to WM_SETCURSOR to handle (re)setting the cursor. Does your control handle that message, or do anything that would prevent the message from being sent to the parent window?

http://trac.wxwidgets.org/browser/wxWidgets/trunk/src/msw/window.cpp#L3370
http://trac.wxwidgets.org/browser/wxWidgets/trunk/src/msw/window.cpp#L4166

If that doesn't help then you may want to try wx.lib.activex instead of wx.lib.activexwrapper as it is a little less hacky.

···

On 7/21/11 4:48 AM, Johannes wrote:

--
Robin Dunn
Software Craftsman

wx responds to WM_SETCURSOR to handle (re)setting the cursor. Does your
control handle that message, or do anything that would prevent the
message from being sent to the parent window?

I don't think so. My code does not handle WM_SETCURSOR directly. Only
the base class might handle it?

BOOL ret = COleControl::OnWndMsg(message, wParam, lParam, pResult);

The return value for the WM_SETCURSOR message is always TRUE and I
receive this event on moving in my panel independently whether it
shows the correct or wrong cursor. I also tried to return FALSE
without any change in behavior.

What can be a reason for the message not being sent to the parent
window?

If that doesn't help then you may want to try wx.lib.activex instead of
wx.lib.activexwrapper as it is a little less hacky.

I thought about that and actually give it a try, but I think that I
can't use it in my setup. My code is heavily dependant on the pywin32
package and I fear to mix this stuff with the comtypes stuff used by
the wx.lib.activex module. Additionally everything except of the
cursor is working fine.

How can I setup wxPython in order to debug into the wxWidget code? Or
simpler, how can I build a modified wxwidget release library
compatible to wxPython in order to add some logging?

Best,
Johannes

···

On Jul 21, 5:53 pm, Robin Dunn <ro...@alldunn.com> wrote:

On 7/21/11 4:48 AM, Johannes wrote:

What are your goals for having “a wx element [ a control ?] with minimum
and maximum sizes… as well as being proportional[ly expandible]” ? What do you want to happen when the control reaches either its minimum or maximum ? What is supposed to happen with the other controls at these times ?

I think you probably want the Frame to have minimum and maximum sizes. Sizers
and Windows have the method .SetMinSize() / MaxSize(), but I don’t think it is functional in Panels. You can call it like you already, but it doesn’t do anything.

You can try this approach: When the BLUE panel (I presume) reaches its minimum size, add in the widths and heights of the other 2 panels. This is the minimum Frame Client width. Do the same with the vertical / height dimensions. --> The ratio of the BLUE panel height to GREEN panel height is 2:1. The RED is fixed at 50. So, if you want BLUE to be a
minimum of 100 pixels, the RED will always 50 and GREEN must be 25, This is 175 pixels, total height. So, set the minimum Frame height accordingly.

There is a method wx.Frame.SetMinSize(), but unfortunately, no wx.Frame.SetMinClientSize(). You can use a “trick” to get the Frame to do what you want it to: First, determine what you want the minimum horizontal size to be. Let’s use 200 pixels for now:

self.SetClientSize( (200, 175) )
selfFrameSize = self.GetSize()
self.SetMinSize ( (selfFrameSize) )

Do the same for the max Frame size. Remember to set the Frame size back to what you want its initial size to be.

By the way, you might want to give the 3 panels 3 different names, otherwise you give up the ability to reference the first two in the future.

Hope this helps.
Ray Pasco

Sorry, posted in the wrong thread.

wx responds to WM_SETCURSOR to handle (re)setting the cursor. Does your
control handle that message, or do anything that would prevent the
message from being sent to the parent window?

I don't think so. My code does not handle WM_SETCURSOR directly. Only
the base class might handle it?

BOOL ret = COleControl::OnWndMsg(message, wParam, lParam, pResult);

The return value for the WM_SETCURSOR message is always TRUE and I
receive this event on moving in my panel independently whether it
shows the correct or wrong cursor. I also tried to return FALSE
without any change in behavior.

What can be a reason for the message not being sent to the parent
window?

I don't know.

If that doesn't help then you may want to try wx.lib.activex instead of
wx.lib.activexwrapper as it is a little less hacky.

I thought about that and actually give it a try, but I think that I
can't use it in my setup. My code is heavily dependant on the pywin32
package and I fear to mix this stuff with the comtypes stuff used by
the wx.lib.activex module. Additionally everything except of the
cursor is working fine.

How can I setup wxPython in order to debug into the wxWidget code? Or
simpler, how can I build a modified wxwidget release library
compatible to wxPython in order to add some logging?

Build instructions are on the website and in the source tree. Be sure you get the right one, there are different instructions for 2.8 and 2.9. Currently they expect you to do either all debug (wxWidgets, wxPython and Python) or all release. This is because of the different debug/release runtime libraries enforced upon us by MS. It is possible however to build a debug wxWidgets and wxPython that should work with the release Python (so you won't have to also build all _d versions of the other extension modules you use) but it's been a long time since I've done it. You should just need to make sure that even though you are using debug flags that the release runtime libraries will continue to be used. IOW, you should see /MD on the compile command lines, not /MDd. For wxWidgets this is possible by fiddling with the flags passed to nmake, look in config.vc for details. For wxPython you might need to hack config.py and/or setup.py a little.

···

On 7/22/11 3:36 AM, Johannes wrote:

On Jul 21, 5:53 pm, Robin Dunn<ro...@alldunn.com> wrote:

On 7/21/11 4:48 AM, Johannes wrote:

--
Robin Dunn
Software Craftsman