滚动时wxScrolledWindow中的图像损坏

时间:2018-02-17 21:29:54

标签: c++ wxwidgets

我想使用wxScrolledWindow在wxSplitterWindow中查看一个图像。 我从wxPanel派生了类,我将其添加到wxScrolledWindow中。但结果不是我想要的。(

class ImagePanel : public wxPanel
{
public:
    //ImagePanel(wxFrame* parent);
    ImagePanel(wxWindow* parent);
    void paintEvent(wxPaintEvent& event);
    void paintNow();

    void setBitmap(wxBitmap& imBitmap);
    void setBitmap(wxImage& img);

    int GetHeight();
    int GetWidth();

    void render(wxDC& dc);

    DECLARE_EVENT_TABLE()
private:
    wxBitmap curBitmap;
};

绘制事件:

void ImagePanel::paintEvent(wxPaintEvent& event)
{
    wxBufferedPaintDC dc(this);
    render(dc);
}

这就是我将接口写入主框架构造函数的方法:

topSizer = new wxBoxSizer(wxVERTICAL);

    topSplitter = new wxSplitterWindow(this,ID_TOPSPLITTER,wxDefaultPosition,wxDefaultSize,wxSP_LIVE_UPDATE|wxSP_3D);
    topSizer->Add(topSplitter,1,wxALL|wxEXPAND,0);

    imagePanel = new wxPanel(topSplitter,ID_IMAGEPANEL);
    imageSizer = new wxBoxSizer(wxVERTICAL);
    imagePanel->SetSizer(imageSizer);
    optionPanel = new wxPanel(topSplitter,ID_OPTIONPANEL);
    optionSizer = new wxBoxSizer(wxVERTICAL);
    optionPanel->SetSizer(optionSizer);
    topSplitter->SplitVertically(imagePanel, optionPanel);
    topSplitter->SetMinimumPaneSize(200);

    //===========================================
    //image panel interface
    imageScWindow=new wxScrolledWindow(imagePanel,ID_IMAGESCWINDOW,wxDefaultPosition,wxDefaultSize,
                                       wxVSCROLL|wxHSCROLL|wxALL|wxALWAYS_SHOW_SB|wxFULL_REPAINT_ON_RESIZE);
    imgArea = new ImagePanel(imageScWindow);
    imageSizer->Add(imageScWindow,1,wxEXPAND,0);

    scrollSizer = new wxBoxSizer(wxVERTICAL);
    imageScWindow->SetSizer(scrollSizer);
    scrollSizer->Add(imgArea,1,wxEXPAND,0);
    imageScWindow->SetTargetWindow(imgArea);

这是加载图片的功能:

void MainFrame::Setpic(wxCommandEvent& event)

{
    wxString path = GetCurrentWorkingDir()+wxT("\\")+tmptxt1->GetValue();
    wxImage img(path);
    wxBitmap imBitmap(img,-1);
    imgArea->setBitmap(imBitmap);
    imageScWindow->SetScrollbars(1,1,imgArea->GetWidth(),imgArea->GetHeight());
    imageScWindow->Refresh();
}

这就是我得到的: 的 https://i.imgur.com/x1GIlrl.png

我也试过在构造函数中这样做,没有SetTargetArea:

//===========================================
    //image panel interface
    imageScWindow=new wxScrolledWindow(imagePanel,ID_IMAGESCWINDOW,wxDefaultPosition,wxDefaultSize,
                                       wxVSCROLL|wxHSCROLL|wxALL|wxALWAYS_SHOW_SB|wxFULL_REPAINT_ON_RESIZE);
    imgArea = new ImagePanel(imageScWindow);
    imageSizer->Add(imageScWindow,1,wxEXPAND,0);

    scrollSizer = new wxBoxSizer(wxVERTICAL);
    imageScWindow->SetSizer(scrollSizer);
    scrollSizer->Add(imgArea,1,wxEXPAND,0);

然后图像显示正确,但如果我更改帧大小或移动分割器,滚动条消失,我必须再次设置它们。 然后我试着这样做:

int prvx,prvy;
void ImagePanel::paintEvent(wxPaintEvent& event)
{
    reinterpret_cast<wxScrolledWindow*>(this->GetParent())->GetViewStart(&prvx,&prvy);
    reinterpret_cast<wxScrolledWindow*>(this->GetParent())->SetScrollbars(1,1,curBitmap.GetWidth(),curBitmap.GetHeight());
    reinterpret_cast<wxScrolledWindow*>(this->GetParent())->Scroll(wxPoint(prvx,prvy));
    wxBufferedPaintDC dc(this);
    render(dc);
}

它正确显示,但在滚动时滞后,即使在wxScrolledWindow中没有wxFULL_REPAINT_ON_RESIZE也是如此。它在paint事件中的原因是:如果我将它添加到OnSize事件中,程序崩溃。怎么办?

1 个答案:

答案 0 :(得分:1)

我不知道从哪里开始回答你的问题。这是一个框架的最小样本,它有一个分割器,左边是位图,右边是面板。我希望你能够调整这个样本来做你需要的。

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif

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

class MyFrame : public wxFrame
{
    public:
        MyFrame( wxWindow* parent, int id = wxID_ANY, wxString title = "Demo",
                 wxPoint pos = wxDefaultPosition, wxSize size = wxDefaultSize,
                 int style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
    private:
        void OnScrollPaint( wxPaintEvent& event );

        wxScrolledCanvas* m_canvas;
        wxBitmap m_bitmap;
};

MyFrame::MyFrame( wxWindow* parent, int id, wxString title, wxPoint pos,
                  wxSize size, int style )
        :wxFrame( parent, id, title, pos, size, style )
{
    m_bitmap=wxBitmap ("test.png", wxBITMAP_TYPE_PNG   );

    wxSplitterWindow* m_splitter1
        = new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition,
                                wxDefaultSize, wxSP_LIVE_UPDATE );

    m_canvas = new wxScrolledCanvas( m_splitter1, wxID_ANY, wxDefaultPosition,
         wxDefaultSize, wxSTATIC_BORDER|wxHSCROLL|wxVSCROLL );

    m_canvas->SetScrollRate( 5, 5 );
    m_canvas->SetVirtualSize(m_bitmap.GetWidth(), m_bitmap.GetHeight());
    m_canvas->SetBackgroundStyle(wxBG_STYLE_PAINT);
    m_canvas->Bind( wxEVT_PAINT, &MyFrame::OnScrollPaint , this );

    wxPanel* m_panel2 = new wxPanel( m_splitter1, wxID_ANY, wxDefaultPosition,
        wxDefaultSize, wxSTATIC_BORDER|wxTAB_TRAVERSAL );

    m_splitter1->SplitVertically( m_canvas, m_panel2, GetSize().x/2 );
}

void MyFrame::OnScrollPaint( wxPaintEvent& event )
{
    wxAutoBufferedPaintDC dc(m_canvas);
    m_canvas->DoPrepareDC(dc);
    dc.Clear();
    dc.DrawBitmap(m_bitmap,0,0);
}

class MyApp : public wxApp
{
    public:
        virtual bool OnInit()
        {
            wxInitAllImageHandlers();
            MyFrame* frame = new MyFrame(NULL);
            frame->Show();
            return true;
        }
};

wxIMPLEMENT_APP(MyApp);

要运行此功能,请务必更改&#34; test.png&#34;在第35行中显示计算机上实际图像文件的名称(如果图像文件不是png,则更改wxBITMAP_TYPE_PNG)。

重要的部分是:

  1. 将画布的背景样式设置为wxBG_STYLE_PAINT,如第46行所示。
  2. 在paint处理程序中,调用paintdc上的DoPrepareDC方法。
  3. 顺便说一下,我的样品中显示的油漆处理程序并不是很好。它每次都绘制整个位图。一个更好的方法是获取更新区域,只重绘所需的部分,但我想保持这个简单。