wxScrolledWindow - Scrollproblem und ein anderes....



  • Hi.
    Ich hab ein Problem mit meinen wxScrolledWindow. Am besten ich paste euch mal den kompletten Code:

    /*************************** .h ***************************/
    
    // Represents the Line-Buffer
    struct CLineBuffer
    {
        wxString Line;
        wxString Prompt;
        bool NeedsPrompt;
    };
    
    /**
        The CCanvas represents the drawable Area of the Console. 
        It is responsible for all drawings, scrolling and the Logic behind it.
        It also manages the Buffers of the Console.
    **/        
    class CCanvas : public wxScrolledWindow
    {
        typedef std::map<int, CLineBuffer> CLineMap;
    
    public:
        CCanvas() : wxScrolledWindow(), m_currentln(0) {}
        CCanvas( wxWindow *parent, wxWindowID, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize );
        virtual ~CCanvas();
    
        // Events
        virtual void OnPaint(wxPaintEvent& event);
        virtual void OnKeyDown(wxKeyEvent& event);
    
        // Setters
        void SetFont(wxFont& font)                { CSettings().Font = font;           }
        void SetFontColour(const wxColour& col)   { CSettings().FontColor = col;       }
        void SetBGColor(const wxColour& col)      { CSettings().BackgroundColor = col; }
    
        // Buffer Access
        const int&  BufferGetCurrentLine() const          { return m_currentln;                      }    
        wxString&   BufferGetLine(const int& _ln )        { return m_buffer[_ln].Line;               }
        void        BufferDeleteLast()                    { m_buffer[m_currentln].Line.RemoveLast(); }
        void        BufferRemoveAt(int pos)               { m_buffer[m_currentln].Line.Remove(pos);  }
        void        BufferAddString(wxChar _buf)          { m_buffer[m_currentln].Line += _buf;      }
        void        BufferAddString(const wxString& _buf) { m_buffer[m_currentln].Line += _buf;      }
        void        BufferNewLine(bool prompt = true);
        void        BufferReset();    
    
        CCommandLineInterpreter* GetInterpreter() { return m_interpreter; }
    
    private:
        CLineMap    m_buffer;
        int         m_currentln;
        wxString    m_prompt;
    
        CCommandLineInterpreter* m_interpreter;
    
        DECLARE_EVENT_TABLE();
        DECLARE_DYNAMIC_CLASS(CCanvas);
    };
    
    /*************************** .cpp  ***************************/
    /*
     *  QConsole - A Win32 Console
     *  Copyright (C) 2008 QConsole Team
     *
     *  This program is free software: you can redistribute it and/or modify
     *  it under the terms of the GNU General Public License as published by
     *  the Free Software Foundation, either version 3 of the License, or
     *  (at your option) any later version.
     *
     *  This program is distributed in the hope that it will be useful,
     *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     *  GNU General Public License for more details.
     *
     *  You should have received a copy of the GNU General Public License
     *  along with this program.  If not, see http://www.gnu.org/licenses/.
     *
     *  -------------------------------------------------------------------
     *
     *  File    : CCanvas.cpp
     *  Author  : scorcher24
     *  Purpose : Holds the Canvas of the Application
     *
     *  -------------------------------------------------------------------
     */ 
    #include "stdafx.h"
    
    BEGIN_EVENT_TABLE(CCanvas, wxScrolledWindow)
        EVT_PAINT(CCanvas::OnPaint)
        EVT_CHAR(CCanvas::OnKeyDown)
    END_EVENT_TABLE();
    
    IMPLEMENT_DYNAMIC_CLASS(CCanvas, wxScrolledWindow);
    
    /////////////////////////////////////////
    // Constructor
    // 
    // Constructs the Canvas
    /////////////////////////////////////////
    CCanvas::CCanvas( wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size )
    : wxScrolledWindow(parent, id, pos, size, wxVSCROLL), m_currentln(0)
    {
        // Setup Window
        this->SetBackgroundStyle(wxBG_STYLE_COLOUR);
        this->SetBackgroundColour(CSettings().GetBackgroundColour());
        this->Refresh(true);
        this->SetVirtualSize(size);
        this->SetScrollRate(0, 10);
        this->SetCaret(new wxCaret(this, 10, 1));
        this->GetCaret()->Show();
    
        BufferReset();
    
        m_interpreter = new CCommandLineInterpreter(this);
    }
    
    /////////////////////////////////////////
    // DeConstructor
    // 
    // Deletes the Canvas
    /////////////////////////////////////////
    CCanvas::~CCanvas()
    {
        m_buffer.clear();
        wxDELETE(m_interpreter);
    }
    
    void CCanvas::BufferReset()
    {
        m_buffer.clear();
        m_currentln = 0;
    
        m_buffer[m_currentln].NeedsPrompt = false;
        this->BufferAddString(wxString(wxT("QConsole - A console for Win32. Press F1 or type 'help' for Help.")));
        this->BufferNewLine(false);
        this->BufferNewLine(true);
    }
    
    void CCanvas::OnKeyDown(wxKeyEvent& event)
    {
        bool action = true;
    
        switch(event.GetKeyCode())
        {
        case WXK_BACK:
            {
                this->BufferDeleteLast();
                action = false;
                break;
            }
        case WXK_RETURN:
            {
                wxString cmd = m_buffer[m_currentln].Line.Trim();
                cmd = cmd.BeforeFirst(' ');
    
                wxString args = m_buffer[m_currentln].Line.Trim();
                args = args.AfterFirst(' ');
    
                eCI_ErrorCode error = m_interpreter->ExecuteRawString(cmd, args); 
                if ( error == CI_EMPTY || error == CI_OK )
                {
                    this->BufferNewLine(true);
                }
                else if ( error == CI_ERROR )
                {
                    this->BufferNewLine(false);
                    this->BufferAddString(wxString(wxT("Unknown Command.")));
                    this->BufferNewLine(true);
                }
                else if ( error == CI_TOOMUCHARGUMENTS )
                {
                    this->BufferNewLine(false);
                    this->BufferAddString(wxString(wxT("Command has too much Arguments.")));
                    this->BufferNewLine(true);
                }
                else if ( error == CI_TOOFEWARGUMENTS )
                {
                    this->BufferNewLine(false);
                    this->BufferAddString(wxString(wxT("Command has too few Arguments.")));
                    this->BufferNewLine(true);
                }
                action = false;
                break;
            }
        case WXK_HOME:
        case WXK_END:
        case WXK_PAGEDOWN:
        case WXK_PAGEUP:
        case WXK_DELETE:
        case WXK_UP:
        case WXK_DOWN:
        case WXK_LEFT:
        case WXK_RIGHT:
            {
                action = false;
                break;
            }
        }
    
        if ( event.AltDown() || !isprint(event.GetRawKeyCode()) || event.GetKeyCode() >= WXK_F1 )
        {
            action = false;
        }
    
        if ( action )
        {                
            wxString key = event.GetUnicodeKey();
    
            // GetUnicodeKey() returns captilized chars only (true?),
            // so we lower them if there is not shift nor caps lock pressed
            if ( event.ShiftDown() == false )
            {
                key.LowerCase();
            }
    
            this->BufferAddString(key);
        }
        this->Refresh();
    
        event.Skip();
    }
    
    /////////////////////////////////////////
    // OnPaint()
    // 
    // Paints everything to the Canvas.
    /////////////////////////////////////////
    void CCanvas::OnPaint(wxPaintEvent& event)
    {    
        wxPaintDC dc(this);    
        PrepareDC(dc);
        wxCaretSuspend cs(this);
    
        dc.Clear();
        dc.SetFont(CSettings().GetFont());    
        dc.SetTextForeground(CSettings().GetFontColour());
    
        int ySize = dc.GetCharHeight();
    
        // Draw Lines
        for (wxUint32 i = 0; i < m_buffer.size();i++)
        {
            wxString line;
            if ( m_buffer[i].NeedsPrompt == true )
            {
                line = m_buffer[i].Prompt + m_buffer[i].Line;
            }
            else
            {
                line = m_buffer[i].Line;
            }
    
            int x = 0; int y = 0; int hLine = 0;
            dc.GetMultiLineTextExtent(line, &x, &y, &hLine);
            hLine = hLine * i;
    
            dc.DrawText(line, 0, hLine);
            this->GetCaret()->Move(x, hLine + ySize ); // We want the caret at the bottom                        
        }
    
        // Update Virtual size
        this->SetVirtualSize(0, (ySize * m_currentln) + dc.GetCharHeight() );
    }
    
    /////////////////////////////////////////
    // BufferNewLine()
    // 
    // Inserts a new line and scrolls the 
    // canvas to the current position
    /////////////////////////////////////////
    void CCanvas::BufferNewLine( bool prompt )
    { 
        ++m_currentln;
        m_buffer[m_currentln].NeedsPrompt = prompt;
        m_buffer[m_currentln].Prompt = wxGetCwd() + wxT(":>");
        // This creates the Line in the map, 
        // otherwise it will not be painted until you press a key.
        m_buffer[m_currentln].Line += wxEmptyString; 
    
        int x = 0; int y = 0;
        this->GetVirtualSize(&x, &y);
        y += this->GetCharHeight();
        this->Scroll(0, y );    
    }
    

    Hier das Problem:
    Die Funktion BufferNewLine() soll eine neue Zeile erzeugen und das Fenster an die unterste Position scrollen, so damit man alles gut sehen kann, während man tippt. Das funktioniert leider nicht richtig. Es ist immer zu wenig, so dass die aktuelle Zeile wo getippt wird, zu weit unten steht. Ich hab schon versucht Scroll() größere Werte zu übergeben, aber das funktioniert nicht.
    Nachdem das ganze aus dem sichtbaren Bereich gelaufen ist, fehlt auch der Cursor und ist nicht mehr zum erscheinen zu bewegen.
    Bin ein wenig ratlos.

    Die 2te Sache ist wahrscheinlich etwas einfacher, hehe. Ich hab ein wxTaskbarIcon installiert und möchte bei einem einfachen Klick auf dieses das Fenster wieder in Vordergrund bringen lassen bzw anzeigen (Fenster wird nicht in der Taskleiste angezeigt und in Alt-Tab auch nicht). Hierfür hab ich keine Funktion gefunden. wxTopLevelWindow::RequestUserAttention() bringt nichts, da das nur das Fenster in der Taskleiste flasht, aber da isses wie gesagt nicht drin. wxWindow::SetFocus() war ebenfalls Erfolglos.
    Danke für eure Hilfe 🙂 🕶
    rya.



  • Also das ist zuverlässig reproduzierbar. Es fehlt jede 2te neue Zeile (nach Enter) 1-2 Zeilen die nicht gescrollt werden. Wenn man größere Ausgaben hat, wie als Beispiel gcc --help, dann scrollt das Fenster gar nicht, obwohl ja eine neue Zeile angelegt wird.
    rya.


  • Mod

    Hab gerade leider nicht die Zeit mir das alles anzusehen, die 250 Zeilen code sind dann doch was viel...
    Kannst du evtl. mal die entscheidenen Codeblöcke hervorheben und posten?

    phlox



  • void CCanvas::BufferNewLine( bool prompt ) 
    { 
        ++m_currentln; 
        m_buffer[m_currentln].NeedsPrompt = prompt; 
        m_buffer[m_currentln].Prompt = wxGetCwd() + wxT(":>"); 
        // This creates the Line in the map, 
        // otherwise it will not be painted until you press a key. 
        m_buffer[m_currentln].Line += wxEmptyString; 
    
        int x = 0; int y = 0; 
        this->GetVirtualSize(&x, &y); 
        y += this->GetCharHeight(); 
        this->Scroll(0, y );     
    }
    

    Hier wird die neue Zeile angelegt.
    Wie gesagt, ist nach dem Scrollen immer eine Zeile zuwenig, d.h. es ist die Zeile die aktuell getippt wird, ausserhalb des Bildes :(.
    Lässt sich auch mit ScrollLine( this->GetScrollLines() ); reproduzieren.
    rya.


  • Mod

    Hm, und die Map dort ist ok?
    Fängt m_currentln bei 0 an?

    phlox



  • Ja, mit der MAP ist alles ok und ja, m_currentln fängt bei 0 an. Es wird ja aus der Map alles gerendert. (Die Map stellt die Zeilen dar und ist als std::map <int (Zeilennummer), CLine (struct siehe oben)> definiert).
    Das Problem ist im wxForum.shadonet.com auch bekannt. Da gibts mehrere unbeantwortete Threads im Forum mit dem selben Problem. Hab auch schon im #wxwidgets-channel im IRC nachgefragt, dort hat auch niemand darauf geantwortet :(. Die Samples hab ich auch durch, konnte da aber keine großen Unterschiede zu meinem Code feststellen.
    rya.


  • Mod

    Was passierst wenn du den Scrollbereich im y bereich um eine Zeile größer machst, als er eigentlich ist?



  • Wie oben bereits geschrieben habe: Nichts. Also wenn ich den y-Wert den ich Scroll() übergebe größer mache. Wenn ich SetVirtualSize() größer mache, ist das ebenfalls nicht von Erfolg gekrönt.
    rya.



  • Ok habs gefunden ich Idiot.
    Man sollte SetVirtualSize ausführen, nachdem man Text angehängt hat und das nicht im OnPaint()-Event. 😞 Funkt jetzt.

    rya.


Anmelden zum Antworten