How to place menu bar on frame's title bar and keep "minimize, maximize and close" buttons & and dragging?

Hi,

Recent softwares like Pycharm has placed the menu bar on the frame’s title bar, so that it saves on the space consumed by title bar. Plus the title bar still has the “minimize, maximize and close” buttons. And the user still can move the window by clicking and dragging the title bar. (I attached an image)

Does anyone know how to do it with wxpython?

You can hide the default title and draw your own using the panel.
An example of moving a window with a custom title (the example is not very good but the essence can be understood).

certainly no copy & paste, but a good start (especially if one hates OO) :angry:
developed would qualify for the Wiki, I think…

if you drag the original frame behind the dialog so that the title bars are on top of each other, release the mouse and drag the dialog then both are dragged: is that a feature? :roll_eyes:

titel_bar_menu_1.py (1.1 KB)

Does somebody have a real complete demo - or code that has a menu in the title bar?

From copy & paste (true) ,
menuBar_in_titleBar.zip (183.6 KB)
Tested py 3.8.5 / wxPy 4.1.1 / Win10

It’s an amateur job, it’s imperfect, but it works.
You can surely do much better.
Or native source code here.

I hope no one pops up moaning about too many dependencies! and I just wonder if everybody knows what to copy & paste (???) into the own app?

But I suppose I should invest more time into c&p to get the hang of it :upside_down_face:

P.S. I do have to say that this example is much more profound than your last one about the singleton Frame, but you have to admit that the Russian got the dragging part of a modified standard Frame! (for industry most important) quite well (and I think that was all about that post!)

On Ubuntu linux gnome 3 I still get a title bar???

Unfortunately, i don’t have an answer for you. You must ask a Linux specialist.
I hope there a solution for you!

there are goers & doers and if you want something Dunn go to … :wink:

In titlebar.pyw I changed the style setting of MyFrame to just wx.STAY_ON_TOP.

class MyFrame(wx.Frame):
    """
    Thanks to Robin Dunn.
    """
    def __init__(self):
        # style = (wx.CLIP_CHILDREN | wx.CLOSE_BOX |
        #          wx.MINIMIZE_BOX | wx.SYSTEM_MENU |
        #          wx.RESIZE_BORDER | wx.NO_FULL_REPAINT_ON_RESIZE|
        #          wx.STAY_ON_TOP)
        style = wx.STAY_ON_TOP
        super(MyFrame, self).__init__(None,
                                      -1,
                                      title="",
                                      style=style)

When I run it on Python 3.8.5 + wxPython 4.1.1 gtk3 (phoenix) wxWidgets 3.1.5 + Linux Mint 20.1, the frame is displayed without the native title bar. I can move the frame by dragging the pseudo-title bar and the close button does close the frame. However, I’m getting a lot of AssertionErrors like this:

Traceback (most recent call last):
  File "/home/richardt/Development/python/exp/hci/wxpython/discuss_wxpython/menubar_in_titlebar/menuBar_in_titleBar/rectshapedbitmapbuttonTwo.py", line 993, in OnPaint
    self._sbbChildBmp = dc.GetAsBitmap()
wx._core.wxAssertionError: C++ assertion ""Assert failure"" failed at /home/wxpy/wxPython-4.1.1/ext/wxWidgets/src/gtk/dc.cpp(86) in DoGetAsBitmap(): DoGetAsBitmap not implemented

I can confirm RichardT I too get the same results. This is an interesting UI for some other frames that I would like to use in the future. I hope we can get this fixed. I will have some time to work on this at the end of this week. The error appears to being coming from the rectshapedbitmapbutton.py.
I’m running wxPython 4.1.1, pythong 3.8.5, ubuntu 20.04

a Russian post + trial & error :dizzy_face:

custom_titel_bar.py (2.7 KB)

1 Like

Hi,

Yet another titlebar.
It may be necessary to adjust the position and size depending on the OS.

import wx

class TitleBar(wx.Frame):
    def __init__(self, parent, menubar, **kwargs):
        super().__init__(parent,
            style=wx.FRAME_FLOAT_ON_PARENT|wx.NO_BORDER,
            size=(80,18), **kwargs)
        
        self.SetMenuBar(menubar)
        self.max_width = self.Size[0]
        self.min_pos = 32
        
        self.Parent.Bind(wx.EVT_MOVE, self.OnResize)
        self.Parent.Bind(wx.EVT_SIZE, self.OnResize)
    
    def OnResize(self, evt):
        x = self.Size[0]
        w = self.Parent.Size[0]
        p = w-x-150
        if p < self.min_pos:
            self.SetSize(self.max_width + p - self.min_pos, -1)
            p = self.min_pos
        self.Move(self.Parent.ScreenPosition + (p, 13))
        evt.Skip()

class TestFrame(wx.Frame):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        menubar = wx.MenuBar()
        menu = wx.Menu()
        exit = menu.Append(wx.ID_EXIT, 'Exit\tCtrl-w')
        self.Bind(wx.EVT_MENU, lambda v: self.Close(), exit)
        menubar.Append(menu, 'File')
        
        self.tb = TitleBar(self, menubar)
        self.tb.Show()
        
        self.Bind(wx.EVT_CHAR_HOOK, self.OnHookChar)
    
    def OnHookChar(self, evt):
        if evt.EventObject is self:
            self.tb.SetFocus()
            evt.EventObject = self.tb
            wx.PostEvent(self.tb.MenuBar, evt) # transfer the event to tb menu
        else:
            evt.Skip()

if __name__ == '__main__':
    app = wx.App()
    frm = TestFrame(None, title="A poor man's title-bar")
    frm.Show()
    app.MainLoop()
1 Like

when you push the frame narrow so that the menu label is halve hidden and then pull it apart again, the hidden part of the label only reappears after focussing the menu :astonished:

Hi da-dada

Thank you for your advice!
To fix this issue, please modify the following lines:

7c7
-             size=(80,18), **kwargs)
+             size=(80,19), **kwargs)
23c23
-         self.Move(self.Parent.ScreenPosition + (p, 13))
+         self.Move(self.Parent.ScreenPosition + (p, 12))

with this hack, the client area of the TitleBar is shown to screen slightly so that it handles the resize event internally (I guess).