wxScrolledWindow do not scroll to focused wxTextCtrl Topic is solved

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.
Harsh
Knows some wx things
Knows some wx things
Posts: 32
Joined: Tue Apr 13, 2021 5:03 am

wxScrolledWindow do not scroll to focused wxTextCtrl

Post by Harsh » Thu Apr 22, 2021 9:39 am

Whenever Scrolled Window get dynamic row it shows scroll bars but do not scroll to focused widget.
I also searched for AutoScroll but no luck.
Here is my Code.

Code: Select all

   wxScrolledWindow *sw=new wxScrolledWindow(this);
    sw->SetScrollRate(5,5);
    wxBoxSizer *scrollBox=new wxBoxSizer(wxVERTICAL);
    
    sw->SetSizer(scrollBox);
    sw->FitInside();
    AddRow();

In AddRow Function : 
void AddRow(){
    wxPanel *p=new wxPanel(sw);
    wxBoxSizer *hbox=new wxBoxSizer(wxHORIZONTAL);

   for(int i=0;i<10;i++){
        hbox->Add(wxTextCtrl(p,wxID_ANY,wxT("")),0,wxALL,5);
    }
    p->SetSizer(hbox);
    scrollBox->Add(p,0,wxExpand);
    scrollBox->Layout();
}
I have tried sw->PostSizeEvent, sw->Scroll(0,(txt->GetRect().GetX()+txt->GetRect().GetHeight())/5);
But Scrolls at wrong position.

Please Help Me [-o< To Solve This Problem.

Thanks In Advance. :D

User avatar
doublemax
Moderator
Moderator
Posts: 16026
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxScrolledWindow do not scroll to focused wxTextCtrl

Post by doublemax » Thu Apr 22, 2021 10:10 am

Code: Select all

txt->GetRect().GetX()
Shouldn't that be GetY() here?
Use the source, Luke!

Harsh
Knows some wx things
Knows some wx things
Posts: 32
Joined: Tue Apr 13, 2021 5:03 am

Re: wxScrolledWindow do not scroll to focused wxTextCtrl

Post by Harsh » Thu Apr 22, 2021 1:55 pm

Sorry for the typo.

Actually I am creating new row on Enter on last text field.

row creates successfully But when it goes beyond view port scrolled window do not scroll to it.

Also used txt->navigate(wxNagivationKeyEvent::IsForward) after AddRow(). It also works.

But still scrolled window do not scroll to focused text field.

User avatar
doublemax
Moderator
Moderator
Posts: 16026
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxScrolledWindow do not scroll to focused wxTextCtrl

Post by doublemax » Thu Apr 22, 2021 1:58 pm

Can you post some compilable code that shows the problem?
Use the source, Luke!

Harsh
Knows some wx things
Knows some wx things
Posts: 32
Joined: Tue Apr 13, 2021 5:03 am

Re: wxScrolledWindow do not scroll to focused wxTextCtrl

Post by Harsh » Thu Apr 22, 2021 2:44 pm

doublemax wrote:
Thu Apr 22, 2021 1:58 pm
Can you post some compilable code that shows the problem?

Code: Select all

//MyFrame.h
#ifndef MYFRAME_H
#define MYFRAME_H
#include<wx/frame.h>
#include<wx/sizer.h>
#include<wx/panel.h>
#include<wx/scrolwin.h>
#include<wx/textctrl.h>

class MyFrame:public wxFrame{
    public:
        MyFrame(const wxString &title);
    private:
        wxPanel *panel,*p;
        wxBoxSizer *vbox,*vbox1,*hbox;
        wxTextCtrl *txt;
        wxScrolledWindow *sw;

        void AddRow();
        void OnKeyDown(wxKeyEvent &event);
};
#endif

Code: Select all

//MyFrame.cpp
#include<MyFrame.h>
#include<wx/textctrl.h>

MyFrame::MyFrame(const wxString &title):wxFrame(NULL,wxID_ANY,title){
    panel=new wxPanel(this);
    vbox=new wxBoxSizer(wxVERTICAL);

    vbox->Add(new wxTextCtrl(panel,wxID_ANY,wxT("")));
    vbox->Add(new wxTextCtrl(panel,wxID_ANY,wxT("")));

    sw=new wxScrolledWindow(panel);
    sw->SetScrollRate(5,5);
    vbox1=new wxBoxSizer(wxVERTICAL);
    AddRow();
    sw->SetSizer(vbox1);
    sw->FitInside();
    vbox->Add(sw,1,wxEXPAND|wxALL,5);

    vbox->Add(new wxTextCtrl(panel,wxID_ANY,wxT("")));
    vbox->Add(new wxTextCtrl(panel,wxID_ANY,wxT("")));
    vbox->Add(new wxTextCtrl(panel,wxID_ANY,wxT("")));
    vbox->Add(new wxTextCtrl(panel,wxID_ANY,wxT("")));
    
    panel->SetSizer(vbox);
}
void MyFrame::OnKeyDown(wxKeyEvent &event){
    event.Skip();
    txt=(wxTextCtrl*)event.GetEventObject();
    if(event.GetKeyCode()==8){
        txt->Navigate(wxNavigationKeyEvent::IsBackward);
    }else if(event.GetKeyCode()==13){
        if(txt->GetId()==1&&!txt->GetParent()->GetNextSibling()){
            AddRow();
        }
        txt->Navigate(wxNavigationKeyEvent::IsForward);
    }
}
void MyFrame::AddRow(){
    p=new wxPanel(sw);
    hbox=new wxBoxSizer(wxHORIZONTAL);

    for(int i=0;i<9;i++){
        txt=new wxTextCtrl(p,wxID_ANY,wxT(""),wxDefaultPosition,wxSize(5,25),wxTE_PROCESS_ENTER);
        txt->Bind(wxEVT_KEY_DOWN,&MyFrame::OnKeyDown,this);
        hbox->Add(txt,1,wxEXPAND|wxALL,5);
    }
    txt=new wxTextCtrl(p,1,wxT("Last Field."),wxDefaultPosition,wxSize(5,25),wxTE_PROCESS_ENTER);
    txt->Bind(wxEVT_KEY_DOWN,&MyFrame::OnKeyDown,this);
    hbox->Add(txt,1,wxEXPAND|wxALL,5);
    p->SetSizer(hbox);

    vbox1->Add(p,0,wxEXPAND);
    vbox1->Layout();
    sw->PostSizeEvent();
}

User avatar
doublemax
Moderator
Moderator
Posts: 16026
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxScrolledWindow do not scroll to focused wxTextCtrl

Post by doublemax » Thu Apr 22, 2021 4:59 pm

I rewrote your code a bit, this worked for me:
Attachments
myframe.cpp
(2.08 KiB) Downloaded 26 times
myframe.h
(452 Bytes) Downloaded 23 times
Use the source, Luke!

Harsh
Knows some wx things
Knows some wx things
Posts: 32
Joined: Tue Apr 13, 2021 5:03 am

Re: wxScrolledWindow do not scroll to focused wxTextCtrl

Post by Harsh » Thu Apr 22, 2021 5:13 pm

doublemax wrote:
Thu Apr 22, 2021 4:59 pm
I rewrote your code a bit, this worked for me:
Thanks😊😊😊😊😊
I will try.

Harsh
Knows some wx things
Knows some wx things
Posts: 32
Joined: Tue Apr 13, 2021 5:03 am

Re: wxScrolledWindow do not scroll to focused wxTextCtrl

Post by Harsh » Thu Apr 22, 2021 8:37 pm

doublemax wrote:
Thu Apr 22, 2021 4:59 pm
I rewrote your code a bit, this worked for me:
1. My program do not create new line if next row present. Yours do.

2. My Main Issue Is : If you are at last visible row - And you press Enter - Then cursor goes to next line's first text field -
which is just beyond the visible port - But scrolled window do not move(scroll) to make focused element visible.

Please Help Me To Solve This Very Small Issue.

User avatar
doublemax
Moderator
Moderator
Posts: 16026
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxScrolledWindow do not scroll to focused wxTextCtrl

Post by doublemax » Thu Apr 22, 2021 9:06 pm

Harsh wrote:
Thu Apr 22, 2021 8:37 pm
1. My program do not create new line if next row present. Yours do.
Yes, that's a logical bug which should be easy to fix.
Harsh wrote:
Thu Apr 22, 2021 8:37 pm
2. My Main Issue Is : If you are at last visible row - And you press Enter - Then cursor goes to next line's first text field -
which is just beyond the visible port - But scrolled window do not move(scroll) to make focused element visible.
That works for me under Windows. What platform are you using?
Use the source, Luke!

Harsh
Knows some wx things
Knows some wx things
Posts: 32
Joined: Tue Apr 13, 2021 5:03 am

Re: wxScrolledWindow do not scroll to focused wxTextCtrl

Post by Harsh » Fri Apr 23, 2021 4:18 am

doublemax wrote:
Thu Apr 22, 2021 9:06 pm
Harsh wrote:
Thu Apr 22, 2021 8:37 pm
1. My program do not create new line if next row present. Yours do.
Yes, that's a logical bug which should be easy to fix.
Harsh wrote:
Thu Apr 22, 2021 8:37 pm
2. My Main Issue Is : If you are at last visible row - And you press Enter - Then cursor goes to next line's first text field -
which is just beyond the visible port - But scrolled window do not move(scroll) to make focused element visible.
That works for me under Windows. What platform are you using?
Windows10

Harsh
Knows some wx things
Knows some wx things
Posts: 32
Joined: Tue Apr 13, 2021 5:03 am

Re: wxScrolledWindow do not scroll to focused wxTextCtrl

Post by Harsh » Fri Apr 23, 2021 4:19 am

SetFocus on next panel or first textctrl crashing the app

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

Re: wxScrolledWindow do not scroll to focused wxTextCtrl

Post by PB » Fri Apr 23, 2021 7:25 am

FWIW, the code below works for me as expected, i.e., after pressing <Enter> in the last text control, a new text control is added, focused, and scrolled into view. After adding a new control, m_scrolled->FitInside() must be called before textCtrl->Focus().

Code: Select all

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

class MyFrame : public wxFrame
{
public:
    MyFrame() : wxFrame(nullptr, wxID_ANY, "Test")
    {                       
        m_scrolledPanel = new wxScrolledWindow(this, wxID_ANY);
        m_scrolledPanelSizer = new wxBoxSizer(wxVERTICAL);
        
        for ( size_t i = 0; i < 5; ++i )
            AddTextCtrl(false);

        Bind(wxEVT_TEXT_ENTER, &MyFrame::OnTextEnter, this);

        m_scrolledPanel->SetSizer(m_scrolledPanelSizer);
        m_scrolledPanel->FitInside();
        m_scrolledPanel->SetScrollRate(8, 8);

        SetClientSize(FromDIP(wxSize(200, 100)));
    }
private:
    wxScrolledWindow* m_scrolledPanel{nullptr};
    wxBoxSizer*       m_scrolledPanelSizer{nullptr};
    size_t            m_textCtrlCount{0};

    void AddTextCtrl(bool focus)
    {
        wxTextCtrl* textCtrl = new wxTextCtrl(m_scrolledPanel, wxID_ANY, 
                                       wxString::Format("wxTextCtrl #%zu", ++m_textCtrlCount),
                                       wxDefaultPosition, wxDefaultSize,
                                       wxTE_PROCESS_ENTER);

        m_scrolledPanelSizer->Add(textCtrl, wxSizerFlags().Expand().Border());
        m_scrolledPanel->FitInside();

        if ( focus )
            textCtrl->SetFocus();
    }

    void OnTextEnter(wxCommandEvent& event)
    {
        wxWindow* window = dynamic_cast<wxWindow*>(event.GetEventObject());

        if ( !window->GetNextSibling() ) // last control, add a new one
            AddTextCtrl(true);
        else // just go to the next control
            window->Navigate();
    }
};

class MyApp : public wxApp
{
public:
    bool OnInit() override
    {     
        (new MyFrame())->Show();               
        return true;
    }
}; wxIMPLEMENT_APP(MyApp);
wxWidgets 3.1.5, Windows 10.

EDIT
Sorry, I missed that you are not adding a single focusable control but a panel with child controls.

In this case, scrolling is not automatic; however, scrolling manually still seems to work for me in this example code:

Code: Select all

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

class MyFrame : public wxFrame
{
public:
    MyFrame() : wxFrame(nullptr, wxID_ANY, "Test")
    {                       
        m_scrolledPanel = new wxScrolledWindow(this, wxID_ANY);
        m_scrolledPanelSizer = new wxBoxSizer(wxVERTICAL);
        
        for ( size_t i = 0; i < 3; ++i )
            AddTextCtrls(false);

        Bind(wxEVT_TEXT_ENTER, &MyFrame::OnTextEnter, this);

        m_scrolledPanel->SetSizer(m_scrolledPanelSizer);
        m_scrolledPanel->FitInside();
        m_scrolledPanel->SetScrollRate(8, 8);

        SetClientSize(FromDIP(wxSize(600, 200)));
    }
private:
    wxScrolledWindow* m_scrolledPanel{nullptr};
    wxBoxSizer*       m_scrolledPanelSizer{nullptr};
    size_t            m_textPanelCount{0};

    void AddTextCtrls(bool focus)
    {
        wxPanel*    panel = new wxPanel(m_scrolledPanel);
        wxBoxSizer* panelSizer = new wxBoxSizer(wxHORIZONTAL) ;
        wxTextCtrl* textCtrl = nullptr;

        ++m_textPanelCount;
        for ( size_t i = 0; i < 3; ++i )
        {
            textCtrl = new wxTextCtrl(panel, wxID_ANY, 
                                wxString::Format("wxTextCtrl #%zu.%zu", m_textPanelCount, i + 1),
                                wxDefaultPosition, wxDefaultSize,
                                wxTE_PROCESS_ENTER);

            panelSizer->Add(textCtrl, wxSizerFlags().Expand().Border());
        }
        panel->SetSizer(panelSizer);

        m_scrolledPanelSizer->Add(panel, wxSizerFlags().Expand().Border());
        m_scrolledPanel->FitInside();

        if ( focus )
        {
            panel->SetFocus();
            m_scrolledPanel->Scroll(0, panel->GetPosition().y);
        }
    }

    void OnTextEnter(wxCommandEvent& event)
    {
        wxWindow* window = dynamic_cast<wxWindow*>(event.GetEventObject());

        if (  !window->GetNextSibling() &&             // the last control on the last
              !window->GetParent()->GetNextSibling() ) // panel, add a new panel
        {
            AddTextCtrls(true);
        }
        else // just go to the next control
        {
            window->Navigate();
        }
    }
};

class MyApp : public wxApp
{
public:
    bool OnInit() override
    {     
        (new MyFrame())->Show();               
        return true;
    }
}; wxIMPLEMENT_APP(MyApp);
But in your case, do you really need to add a panel as the parent of text controls, instead of adding them as direct children of the wxScrolledWindow?

Obviously, scrolling into view when adding new controls is just a part of the issue. A control should also be scrolled into view whenever it gets focused, which does not happen in the code above. This seems like a deficit in wxScrolledWindow, and I would ask in wx-users if there is a simple solution to this, instead of dealing with it in the user code.

I wonder if it is related to this code:
https://github.com/wxWidgets/wxWidgets/ ... .cpp#L1098

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

Re: wxScrolledWindow do not scroll to focused wxTextCtrl

Post by PB » Fri Apr 23, 2021 4:14 pm

Out of curiousity, I tried if the autoscroll works when I use wxStaticBox instead of wxPanel as the parent of wxTextCtrls, which is then added to the wxScrolledWindow. It works, so the issue does not seem to be related to whether a wxTextCtrl is a direct child of the wxScrolled, its parent being a wxPanel may be the problem.

Code: Select all

#include <wx/wx.h>
#include <wx/scrolwin.h>
#include <wx/statbox.h>

class MyFrame : public wxFrame
{
public:
    MyFrame() : wxFrame(nullptr, wxID_ANY, "Test")
    {
        m_scrolledPanel = new wxScrolledWindow(this, wxID_ANY);
        m_scrolledPanelSizer = new wxBoxSizer(wxVERTICAL);

        for ( size_t i = 0; i < 3; ++i )
            AddTextCtrls(false);

        Bind(wxEVT_TEXT_ENTER, &MyFrame::OnTextEnter, this);

        m_scrolledPanel->SetSizer(m_scrolledPanelSizer);
        m_scrolledPanel->FitInside();
        m_scrolledPanel->SetScrollRate(8, 8);

        SetClientSize(FromDIP(wxSize(600, 200)));
    }
private:
    wxScrolledWindow* m_scrolledPanel{nullptr};
    wxBoxSizer*       m_scrolledPanelSizer{nullptr};
    size_t            m_textGroupsCount{0};

    void AddTextCtrls(bool focus)
    {
        wxStaticBoxSizer* staticBoxSizer = nullptr;
        wxTextCtrl*       textCtrl = nullptr;

        staticBoxSizer = new wxStaticBoxSizer(wxHORIZONTAL, m_scrolledPanel,
                                wxString::Format("Panel #%zu", ++m_textGroupsCount));

        for ( size_t i = 0; i < 3; ++i )
        {
            textCtrl = new wxTextCtrl(staticBoxSizer->GetStaticBox(), wxID_ANY,
                                wxString::Format("wxTextCtrl #%zu.%zu", m_textGroupsCount, i + 1),
                                wxDefaultPosition, wxDefaultSize,
                                wxTE_PROCESS_ENTER);

            staticBoxSizer->Add(textCtrl, wxSizerFlags().Expand().Border());
        }

        m_scrolledPanelSizer->Add(staticBoxSizer, wxSizerFlags().Expand().Border());
        m_scrolledPanel->FitInside();

        if ( focus )
            staticBoxSizer->GetStaticBox()->SetFocus();
    }

    void OnTextEnter(wxCommandEvent& event)
    {
        wxWindow* window = dynamic_cast<wxWindow*>(event.GetEventObject());

        if ( !window->GetNextSibling() &&             // the last control in the last
             !window->GetParent()->GetNextSibling() ) // control group, add a new control group
        {
            AddTextCtrls(true);
        }
        else // just go to the next control
        {
            window->Navigate();
        }
    }
};

class MyApp : public wxApp
{
public:
    bool OnInit() override
    {
        (new MyFrame())->Show();
        return true;
    }
}; wxIMPLEMENT_APP(MyApp);
Once again, I would ask: Do the wxTextCtrls need to have an extra panel as their parent, cannot they be added as direct children of the wxScrolled?

Harsh
Knows some wx things
Knows some wx things
Posts: 32
Joined: Tue Apr 13, 2021 5:03 am

Re: wxScrolledWindow do not scroll to focused wxTextCtrl

Post by Harsh » Fri Apr 23, 2021 7:30 pm

Duplicate of this : viewtopic.php?t=42096 #-o :lol: :lol:

Code: Select all

	scrolledWindow->GetViewStart(&x,&y);
            //txt->ChangeValue(wxString::Format(wxT("%i"),flag1));
            rect=panelRow->GetRect();
            rowPosition=rect.GetY()+rect.GetHeight();
            rect=scrolleWindow->GetRect();
            if(rowPosition>rect.GetHeight()){
                y++;
                scrolledWindow->Scroll(0,y);
            }
Thank You DoubleMax =D> =D> =D> =D>

Thank You All Others For Help. [-o< [-o<

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

Re: wxScrolledWindow do not scroll to focused wxTextCtrl

Post by PB » Fri Apr 23, 2021 7:51 pm

I am stupid so I have no idea how that fixes the issue here, which boils down to "a control does not scroll into view after getting focus"?

Post Reply