User sizable panel?

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
thoray
Knows some wx things
Knows some wx things
Posts: 48
Joined: Sun Oct 18, 2015 9:31 am

User sizable panel?

Post by thoray »

Is there a way to have a panel that is sizable by user using drag and drop? (EDIT: mouse dragging).

I especially need to resize the panel itself and not use a wxSplitterWindow which portions space between two windows, but keeps the total size constant.

wxPython seems to implement this with wx.lib.resizewidget but I'm using C++. Also, in this thread from 2013 it was suggested to "use MDI or wxAUI" but I'd prefer easier solution.

Also, the particular use case here is that I'd like a wxListView that can be resized by user.
Last edited by thoray on Wed Jul 18, 2018 2:13 pm, edited 1 time in total.
Manolo
Can't get richer than this
Can't get richer than this
Posts: 828
Joined: Mon Apr 30, 2012 11:07 pm

Re: User sizable panel?

Post by Manolo »

It's not clear to me what you are talking about. Resize when drag and drop an object (e.g. a bitmap, or text)? Or resize by dragging a border/corner of the window?

For the first case, use a wxDragImage http://docs.wxwidgets.org/trunk/classwx_drag_image.html and after calling EndDrag() you can resize the window (a panel or a control or any wxWindow) by the values you wish.

For the second case, a wxPanel can not be resized that way. Only "top level" windows (which have a border you can drag) can: wxFrame, wxDialog, and those of wxAUI and wxMDI. As a special addition, a wxSplliterWindow allows also user border-dragging.

If you want a control to be resized, just let it be child of a window with border, and use a sizer that takes all the available space. If the control is the only child of a wxFrame then no sizer is needed, the whole client space will be used by the child.
thoray
Knows some wx things
Knows some wx things
Posts: 48
Joined: Sun Oct 18, 2015 9:31 am

Re: User sizable panel?

Post by thoray »

I'm referring to resize by dragging a border/corner of the window. And in a situation where the window is not a "top level" window but a container for controls, like wxPanel or wxWindow.

I guess the answer to the question is then that it not be done unless using wxAUI or wxMDI.

Besides sizable panel, which it seems is not possible, making the control itself sizable by border dragging would also implement the functionality that I'm after, which is having a wxListView whose size can be expanded downwards by border dragging that is one control amongst others in wxPanel/wxWindow.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7479
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: User sizable panel?

Post by ONEEYEMAN »

Hi,
Can't you use an actual wxPanel or (non-modal) wxDialog?
What is the problem with them? Did you try?

Thank you.
thoray
Knows some wx things
Knows some wx things
Posts: 48
Joined: Sun Oct 18, 2015 9:31 am

Re: User sizable panel?

Post by thoray »

ONEEYEMAN wrote:Hi,
Can't you use an actual wxPanel or (non-modal) wxDialog?
What is the problem with them? Did you try?

Thank you.
I did try putting the control inside a wxWindow but all that gave me was e.g. ability to turn on drawing of borders, but not sizing by border dragging.

Using a free standing wxDialog window would allow to resize the control by border dragging, but I want the control to be fixed in a panel and not in a separate window.
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4204
Joined: Sun Jan 03, 2010 5:45 pm

Re: User sizable panel?

Post by PB »

Did you look into wxSashWindow? I have no experience with this class, but AFAIK it will only provide mouse resizing of the child window, the "form" resizing logic, i.e., what happens with other controls in the form would still need to be coded depending on your needs.

TBH, I do not understand the issue from the user point of view. If the user resizes the panel, what happens to the top level window containing it when a more room is needed and when (unlike with a splitter) the space cannot be taken away from the sibling windows? I assume it will become scrollable - top level windows changing their size based on the user resizing their windows are not very common...
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7479
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: User sizable panel?

Post by ONEEYEMAN »

thoray wrote:
ONEEYEMAN wrote: Hi,
Can't you use an actual wxPanel or (non-modal) wxDialog?
What is the problem with them? Did you try?

Thank you.
I did try putting the control inside a wxWindow but all that gave me was e.g. ability to turn on drawing of borders, but not sizing by border dragging.
Which style(s) did you use for the wxWindow?
thoray wrote: Using a free standing wxDialog window would allow to resize the control by border dragging, but I want the control to be fixed in a panel and not in a separate window.
Could you please do some sketch on what do you mean here?
Preferably just an initial setup and what happens after user drag-resize the dialog/panel.

Thank you.
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: User sizable panel?

Post by doublemax »

Unless you're building a GUI editor, i just can't think of any situation where it makes sense to resize an individual control.

You can of course catch the mouse motion event, check if the mouse is near the edge of a control, change the mouse cursor and if the user clicks, you capture the mouse and resize the control.

But what would happen to other controls that may lie next to or below that one control?

What you would usually do in a wxWidgets application would be to put the control in a sizer and allow it to grow in both directions. And if the user wants it bigger, he will increase the main frame and the inner control will grow and occupy the additional space.
Use the source, Luke!
thoray
Knows some wx things
Knows some wx things
Posts: 48
Joined: Sun Oct 18, 2015 9:31 am

Re: User sizable panel?

Post by thoray »

I made a minimal test app to show a case for user sizable control using wxSashWindow. User can drag the middle horizontal slider to show more or less of the list. This way user can free more space to controls after the list or to see more of the list.

If this was implemented with a wxSplitterWindow then controls after the list would get hidden after showing more of the list. Here instead a scrollbar is added to the panel.

Moving the sash doesn't properly size the list, however. I also get some bugged graphics for the sash moving in GTK2. Also, wxSashWindow doesn't seem to support live updates which makes it look non native, although that would be OK if it worked otherwise.
sashwindow.png
usersizablecontrol.cpp
(2.82 KiB) Downloaded 114 times

Code: Select all

#include "wx/wx.h"
#include <wx/sashwin.h>
#include <wx/listctrl.h>

class MyApp : public wxApp
{
public:
    virtual bool OnInit() override;
};

class MyFrame : public wxFrame
{
public:
    MyFrame(const wxString& title);

    void OnQuit(wxCommandEvent& event);
    void OnSashDragged(wxSashEvent& event);
private:
    wxDECLARE_EVENT_TABLE();

wxScrolledWindow* m_p;
wxSashWindow* m_sw;
wxListView* m_list;
};

enum
{
    Minimal_Quit = wxID_EXIT,
    M_SW,
};

wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_SASH_DRAGGED(M_SW, MyFrame::OnSashDragged)
    EVT_MENU(Minimal_Quit,  MyFrame::OnQuit)
wxEND_EVENT_TABLE()

wxIMPLEMENT_APP(MyApp);

bool MyApp::OnInit()
{
    if ( !wxApp::OnInit() )
        return false;

    MyFrame *frame = new MyFrame("Minimal SashWindow Test App");

    frame->Show(true);

    return true;
}

MyFrame::MyFrame(const wxString& title)
       : wxFrame(NULL, wxID_ANY, title)
{
// Add my control panel as scrolled window
m_p = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxSize(100,200), wxBORDER_THEME, "m_p");
m_p->SetScrollRate(5, 5);
wxBoxSizer* bs = new wxBoxSizer(wxVERTICAL);

wxTextCtrl* m_tc = new wxTextCtrl(m_p, wxID_ANY, "My control panel controls", wxDefaultPosition, wxDefaultSize, wxTE_READONLY);

// Add sashwindow for resizing m_list
m_sw = new wxSashWindow(m_p, M_SW, wxDefaultPosition, wxDefaultSize, wxSW_3DSASH, "m_sw");
m_sw->SetSashVisible(wxSASH_BOTTOM,true);
m_list = new wxListView(m_sw, wxID_ANY, wxDefaultPosition, wxDefaultSize);
wxBoxSizer* bs2 = new wxBoxSizer(wxVERTICAL);

wxButton* m_button0 = new wxButton(m_p,wxID_ANY,"button0");
wxButton* m_button1 = new wxButton(m_p,wxID_ANY,"button1");

wxTextCtrl* m_tc2 = new wxTextCtrl(m_p, wxID_ANY, "Drag the sash to alter list size", wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxTE_CENTRE);

// Add first column
wxListItem col0;
col0.SetId(0);
col0.SetText( _("Col0") );
col0.SetWidth(75);
m_list->InsertColumn(0, col0);

// Add 2nd column
wxListItem col1;
col1.SetId(1);
col1.SetText( _("Col1") );
col1.SetWidth(75);
m_list->InsertColumn(1, col1);

// Add list items
wxListItem item;
for (int k=0;k<4;k++)
{
item.SetId(k);
m_list->InsertItem( item );
m_list->SetItem(k,0,"Hello");
m_list->SetItem(k,1,"World");
}

// Add controls to sizers
bs->Add(m_tc,0,wxEXPAND);
bs->Add(m_sw,0,wxEXPAND);
bs2->Add(m_list,0,wxEXPAND);
bs->Add(m_button0,0,wxEXPAND);
bs->Add(m_button1,0,wxEXPAND);
bs->Add(m_tc2,0,wxEXPAND);

// Associate sizers with controls
m_sw->SetSizer(bs2);
m_p->SetSize(GetClientSize());
m_p->SetSizer(bs);
m_p->FitInside();
this->SetSize(400,500);
}

void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
    Close(true);
}

void MyFrame::OnSashDragged(wxSashEvent& event)
{
  wxRect rect = event.GetDragRect();
  std::cout << "new size: " << rect.GetX() << " " << rect.GetY() << std::endl;
  // FIXME: This does not work
  m_sw->SetSize(rect);
}
thoray
Knows some wx things
Knows some wx things
Posts: 48
Joined: Sun Oct 18, 2015 9:31 am

Re: User sizable panel?

Post by thoray »

Now that I have some idea how layout management works in wxWidgets, I managed to fix my minimal sample from 2018:

Code: Select all

 void MyFrame::OnSashDragged(wxSashEvent& event)
 {
   wxRect rect = event.GetDragRect();
-  std::cout << "new size: " << rect.GetX() << " " << rect.GetY() << std::endl;
-  // FIXME: This does not work
-  m_sw->SetSize(rect);
+  wxSize s = rect.GetSize();
+  s.SetWidth(-1); // Don't set fixed minsize horizontally
+  m_sashw->SetInitialSize(s); // Set new fixed minsize vertically for sashwindow
+  m_sw->Layout(); // Layout resized items in scrolledwindow
+  m_sw->FitInside(); // Fit scrolledwindow inside the frame, adding a scrollbar if necessary
 }
The relevant change is in OnSashDragged() but I also improved the sample overall (usersizablecontrol2.zip). Now this wxSashWindow sample fully works.

Since there is no wxSashWindow sample in wxWidgets how about adding one based on this? wxListView has otherwise fixed vertical size so adding user controlled vertical sizing mechanism can make a lot of sense in an application.
Attachments
usersizablecontrol2.zip
(1.46 KiB) Downloaded 100 times
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7479
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: User sizable panel?

Post by ONEEYEMAN »

Hi,
This is a user forum.
You should send an E-mail to wx-dev or wx-users ML to discuss any changes to the wx distribution.

Thank you.
Post Reply