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
Earned a small fee
Earned a small fee
Posts: 13
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: 15917
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
Earned a small fee
Earned a small fee
Posts: 13
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: 15917
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
Earned a small fee
Earned a small fee
Posts: 13
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: 15917
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 12 times
myframe.h
(452 Bytes) Downloaded 12 times
Use the source, Luke!

Harsh
Earned a small fee
Earned a small fee
Posts: 13
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
Earned a small fee
Earned a small fee
Posts: 13
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: 15917
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
Earned a small fee
Earned a small fee
Posts: 13
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
Earned a small fee
Earned a small fee
Posts: 13
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: 2981
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: 2981
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
Earned a small fee
Earned a small fee
Posts: 13
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: 2981
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