How to create such a layout?

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.
User avatar
doublemax
Moderator
Moderator
Posts: 15170
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to create such a layout?

Post by doublemax » Mon Mar 18, 2019 4:50 pm

The problem with a custom wxGridRowHeaderRenderer is the scrollbar that appears if you have more columns:
grid.png
grid.png (2.06 KiB) Viewed 483 times
Which doesn't look very nice IMHO.
Use the source, Luke!

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 4423
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: How to create such a layout?

Post by ONEEYEMAN » Mon Mar 18, 2019 5:29 pm

doublemax,
I will try to play with just labels and spacers in a vertical sizer.
Maybe I will achieve what I want cross-platform.

Thank you.

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2566
Joined: Sun Jan 03, 2010 5:45 pm

Re: How to create such a layout?

Post by PB » Mon Mar 18, 2019 6:39 pm

ONEEYEMAN wrote:
Mon Mar 18, 2019 5:29 pm
I will try to play with just labels and spacers in a vertical sizer.
This may not be easy, assuming the grid is vertically scrollable and one has to deal with it. Sizers and absolute positioning are not a good match....

FWIW, here is what I briefly played with (the labels align with rows only once the row height changes) before I learned this is not the way to go

Code: Select all

#include <wx/wx.h>
#include <wx/grid.h>

class MyFrame: public wxFrame
{
public:   
    MyFrame() : wxFrame (NULL, wxID_ANY, "Test", wxDefaultPosition, wxSize(800, 600))
    {        
        wxPanel* mainPanel = new wxPanel(this);                
                
        const size_t gridRowCount = 7;
        const size_t gridColCount = 12;

        m_gridRowLabelsSizer = new wxBoxSizer(wxVERTICAL);                
        for ( size_t i = 0; i < gridRowCount - 2; ++i )
        {
            wxStaticText* label = new wxStaticText(mainPanel, wxID_ANY, wxString::Format("%zu", i * 100 + 1));
            
            m_gridRowLabelsSizer->Add(label, wxSizerFlags().Border(wxRIGHT).Right());
        }
                
        m_grid = new wxGrid(mainPanel, wxID_ANY);
        m_grid->CreateGrid(gridRowCount, gridColCount);
        m_grid->HideColLabels();
        m_grid->HideRowLabels();

        m_gridLabelsandGridSizer = new wxBoxSizer(wxHORIZONTAL);
        m_gridLabelsandGridSizer->Add(m_gridRowLabelsSizer, wxSizerFlags().Top());        
        m_gridLabelsandGridSizer->Add(m_grid, wxSizerFlags().Top().Proportion(1).Expand());
        
        wxTextCtrl* logCtrl = new wxTextCtrl(mainPanel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 
            wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2);     
        wxLog::SetActiveTarget(new wxLogTextCtrl(logCtrl)); 
                
        wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
        
        mainSizer->Add(m_gridLabelsandGridSizer, wxSizerFlags().Expand().DoubleBorder().Proportion(2));
        mainSizer->Add(logCtrl, wxSizerFlags().Expand().DoubleBorder().Proportion(1));
        mainPanel->SetSizer(mainSizer);

        m_grid->Bind(wxEVT_GRID_ROW_SIZE, &MyFrame::OnGridRowSize, this);
    }
private:
    wxBoxSizer* m_gridLabelsandGridSizer;
    wxBoxSizer* m_gridRowLabelsSizer;
    wxGrid*     m_grid;

    void AdjustGridRowLabels()
    {
        wxCHECK_RET(m_gridRowLabelsSizer->GetItemCount() <= (size_t)m_grid->GetNumberRows(), 
            "number of row labels must not be larger than the number of rows in the grid");

        for ( size_t i = 0; i < m_gridRowLabelsSizer->GetItemCount(); ++i )        
        {
            if ( !m_grid->IsVisible(i, 0, false) )
                break;
            
            m_gridRowLabelsSizer->SetItemMinSize(i, -1, m_grid->GetRowSize(i));
        }

        m_gridLabelsandGridSizer->Layout();        

        for ( size_t i = 0; i < m_gridRowLabelsSizer->GetItemCount(); ++i )
        {        
            wxLogMessage("Row %zu: row height = %d, label height = %d", i, 
                m_grid->GetRowSize(i), m_gridRowLabelsSizer->GetItem(i)->GetSize().GetHeight());            
        }    
    }

    void OnGridRowSize(wxGridSizeEvent& event)
    {
        wxLogMessage("OnGridRowSize");
        AdjustGridRowLabels();
        event.Skip();
    }
};

class MyApp : public wxApp
{
public:         
    bool OnInit()
    {
        (new MyFrame())->Show();               
        return true;
    }   
}; wxIMPLEMENT_APP(MyApp);

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 4423
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: How to create such a layout?

Post by ONEEYEMAN » Mon Mar 18, 2019 7:04 pm

PB,
Yes - the grid is vertically scrollable. And thats the other reason I want to skip label renderer override - I don't want to keep re-assigning those labels on every single vertical scroll.

Why do you say "its not a way to go"?

My screenshot is from MS ACCESS where I'm sure they have only absolute positioning and some magic with the grid and fonts (its M$ only).

I can play with both spacers between labels and row height in the grid to have the same effect.

Thank you.

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2566
Joined: Sun Jan 03, 2010 5:45 pm

Re: How to create such a layout?

Post by PB » Mon Mar 18, 2019 8:01 pm

ONEEYEMAN wrote:
Mon Mar 18, 2019 7:04 pm
Yes - the grid is vertically scrollable. And thats the other reason I want to skip label renderer override - I don't want to keep re-assigning those labels on every single vertical scroll.
Is that necessary, I thought if you use actual row headers they will always match the rows regardless of scrolling, unlike manual labels. I can see only one issue, as doublemax pointed out the scrollbar starts below the labels instead of grid rows.
ONEEYEMAN wrote:
Mon Mar 18, 2019 7:04 pm
Why do you say "its not a way to go"?
I meant not using the sizer for the labels, as this does not work well with absolute sizing and especially positioning.
ONEEYEMAN wrote:
Mon Mar 18, 2019 7:04 pm
My screenshot is from MS ACCESS where I'm sure they have only absolute positioning and some magic with the grid and fonts (its M$ only).
I can play with both spacers between labels and row height in the grid to have the same effect.
We both know that such designs are very brittle and can easily break depending on the OS, theme used, DPIs...

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 4423
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: How to create such a layout?

Post by ONEEYEMAN » Mon Mar 18, 2019 8:46 pm

PB,
PB wrote:
Mon Mar 18, 2019 8:01 pm
ONEEYEMAN wrote:
Mon Mar 18, 2019 7:04 pm
Yes - the grid is vertically scrollable. And thats the other reason I want to skip label renderer override - I don't want to keep re-assigning those labels on every single vertical scroll.
Is that necessary, I thought if you use actual row headers they will always match the rows regardless of scrolling, unlike manual labels. I can see only one issue, as doublemax pointed out the scrollbar starts below the labels instead of grid rows.
Well, that's the problem.
If you start MS ACCESS and open the query designer, the grid can be scrolled vertically, but the labels stays the same and the will not scroll with the other rows.
PB wrote:
Mon Mar 18, 2019 8:01 pm
ONEEYEMAN wrote:
Mon Mar 18, 2019 7:04 pm
Why do you say "its not a way to go"?
I meant not using the sizer for the labels, as this does not work well with absolute sizing and especially positioning.
Well, I won't use anything abolute. The labels will be in the vertical sizer and they will will be next to the grid which will also be inside the sizer.
PB wrote:
Mon Mar 18, 2019 8:01 pm
ONEEYEMAN wrote:
Mon Mar 18, 2019 7:04 pm
My screenshot is from MS ACCESS where I'm sure they have only absolute positioning and some magic with the grid and fonts (its M$ only).
I can play with both spacers between labels and row height in the grid to have the same effect.
We both know that such designs are very brittle and can easily break depending on the OS, theme used, DPIs...
Agreed. But that's why I wrote that it's MS only and they probably do some magic to make it work properly everywhere.
All I need to do is to mimic this with the wxWidgets sizers paradigm...

Thank you.

PB
Part Of The Furniture
Part Of The Furniture
Posts: 2566
Joined: Sun Jan 03, 2010 5:45 pm

Re: How to create such a layout?

Post by PB » Mon Mar 18, 2019 9:17 pm

I only looked at the UI in Access (current Office 365 on monthly channel) now and noticed that the grid there also has frozen rows and only the rows starting with Criteria scroll. So I guess you are out of luck with current wxGrid implementation.... Otherwise, basically the code I posted in my previous post would more or less work.

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 4423
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: How to create such a layout?

Post by ONEEYEMAN » Mon Mar 18, 2019 9:32 pm

PB,
Yes, it would be nice to have this merged.
But lacking that I can try to play with the labels.

Thank you.

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 4423
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: How to create such a layout?

Post by ONEEYEMAN » Tue Mar 19, 2019 4:18 am

Hi,
Well I tried.

Code: Select all

    m_grid = new wxGrid( m_panel, wxID_ANY );
    m_label10 = new wxStaticText( m_panel, wxID_ANY, _( "Column:" ) );
    m_label11 = new wxStaticText( m_panel, wxID_ANY, _( "Sort:" ) );
    m_label12 = new wxStaticText( m_panel, wxID_ANY, _( "Criteria:" ) );
    m_grid->CreateGrid( 4, 0 );
    m_grid->HideColLabels();
    m_grid->HideRowLabels();
    auto *sizer3 = new wxBoxSizer( wxVERTICAL );
    auto *sizer10 = new wxBoxSizer( wxVERTICAL );
    auto *sizer11 = new wxBoxSizer( wxHORIZONTAL );
    sizer10->Add( m_label10, 0, wxEXPAND, 0 );
    sizer10->Add( 10, 10, 0, wxEXPAND, 0 );
    sizer10->Add( m_label11, 0, wxEXPAND, 0 );
    sizer10->Add( 10, 10, 0, wxEXPAND, 0 );
    sizer10->Add( m_label12, 0, wxEXPAND, 0 );
    sizer11->Add( sizer10, 0, wxEXPAND, 0 );
    sizer11->Add( m_grid, 0, wxEXPAND, 0 );
    sizer3->Add( sizer11, 0, wxEXPAND, 0 );
The result does not look so good (Attached). As you can see the grid disappear.

Thank you.
Attachments
Capture1.PNG
Capture1.PNG (1.73 KiB) Viewed 419 times

Post Reply