最小绘画程序的示例代码(MS Paint样式)

时间:2010-08-14 15:52:25

标签: cocoa user-interface gtk wxwidgets paint

我想以MS Paint的风格编写一个绘画程序。

在最基本的层面上,每当用户拖动鼠标时,我都必须在屏幕上画一个点。

def onMouseMove():
    if mouse.button.down:
        draw circle at (mouse.position.x, mouse.position.y)

不幸的是,我的GUI框架出现问题(参见上一页question),我没有足够频繁地获取鼠标移动消息。我正在使用GUI框架wxWidgets和编程语言Haskell。

问题:您能否给我一些示例代码来实现这样一个最小的绘制程序?您的代码最好使用 wxWidgets ,但我也接受GTK +或Cocoa。我不介意任何编程语言,只要我可以在MacOS X上轻松安装它。请包括整个项目,makefile等所有,因为我可能不喜欢在编写语言方面有很多经验。

基本上,我想有一个小例子向我展示如何在wxWidgets或其他GUI框架中正确执行它,所以我可以弄清楚为什么我的Haskell和wxWidgets的组合不能提供合适的鼠标移动频率事件

4 个答案:

答案 0 :(得分:4)

对于Cocoa,Apple提供了一个名为CIMicroPaint的示例,虽然它有点复杂,因为它使用Core Image而不是Quartz 2D。这是一个截图: CIMicroPaint screenshot http://i36.tinypic.com/29mm2vs.jpg

答案 1 :(得分:2)

我知道这是一个古老的问题,但是 - 为了获得平滑的绘图,将画笔的实例放在鼠标的位置并不够简单,因为输入事件的轮询速度几乎没有他们需要平滑的绘画。

绘图线是一个非常有限的解决方案,因为线条是线条,对于绘图应用程序,您需要能够使用自定义位图画笔。

解决方案很简单,你必须在光标的前一个和当前位置之间进行插值,找到两个点之间的线,并通过为两点之间的每个像素添加画笔来插值。

对于我的解决方案,我使用了Qt,所以这里的方法是在最后一个位置和当前位置之间插入一条线,以便顺利地填充它。基本上它找到两点之间的距离,计算增量并使用常规for循环进行插值。

void Widget::drawLine()
{
    QPointF point, drawPoint;
    point = newPos - lastPos;
    int length = point.manhattanLength();
    double xInc, yInc;

    xInc = point.x() / length;
    yInc = point.y() / length;

    drawPoint = lastPos;

    for (int x=0; x < length; ++x) {
        drawPoint.setX(drawPoint.x()+xInc);
        drawPoint.setY(drawPoint.y()+yInc);
        drawToCanvas(drawPoint);
    }
}

这应该会给你带来流畅的效果,而且性能非常好,我甚至在我的Android平板电脑上进行了测试,这是一个非常慢而且迟钝的设备,而且效果非常好。

答案 2 :(得分:1)

像你的眼睛一样,光标在跳跃中移动,所以你需要在光标被记录的每个点之间画线。

答案 3 :(得分:1)

要回答我自己的问题,这里是使用wxWidgets的C ++中的最小绘画示例。我主要收集了Cross-Platform GUI Programming with wxWidgets这本书的片段,该书可以免费在线获取。

绘图尽可能顺利,鼠标事件频率没有问题,如截图所示。请注意,调整窗口大小时图形将丢失。 wxWidgets paint example http://i33.tinypic.com/20rlnw2.jpg

这是C ++源代码,假设在文件minimal.cpp中。

// Name:    minimal.cpp
// Purpose: Minimal wxWidgets sample
// Author:  Julian Smart, extended by Heinrich Apfelmus

#include <wx/wx.h>

// **************************** Class declarations ****************************

class MyApp : public wxApp {
    virtual bool OnInit();
};

class MyFrame : public wxFrame {
  public:
    MyFrame(const wxString& title); // constructor

    void OnQuit(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);
    void OnMotion(wxMouseEvent& event);

  private:
    DECLARE_EVENT_TABLE()     // this class handles events
};

// **************************** Implementation ****************************
// **************************** MyApp
DECLARE_APP(MyApp)      // Implements MyApp& GetApp()
IMPLEMENT_APP(MyApp)    // Give wxWidgets the means to create a MyApp object

// Initialize the application
bool MyApp::OnInit() {
    // Create main application window
    MyFrame *frame = new MyFrame(wxT("Minimal wxWidgets App"));

    //Show it
    frame->Show(true);

    //Start event loop
    return true;
}

// **************************** MyFrame
// Event table for MyFrame
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
    EVT_MENU(wxID_EXIT , MyFrame::OnQuit)
END_EVENT_TABLE()

void MyFrame::OnAbout(wxCommandEvent& event) {
    wxString msg;
    msg.Printf(wxT("Hello and welcome to %s"), wxVERSION_STRING);
    wxMessageBox(msg, wxT("About Minimal"), wxOK | wxICON_INFORMATION, this);
}

void MyFrame::OnQuit(wxCommandEvent& event) {
    Close();
}

// Draw a dot on every mouse move event
void MyFrame::OnMotion(wxMouseEvent& event) {
    if (event.Dragging())
    {
        wxClientDC dc(this);
        wxPen pen(*wxBLACK, 3); // black pen of width 3
        dc.SetPen(pen);
        dc.DrawPoint(event.GetPosition());
        dc.SetPen(wxNullPen);
    }
}

// Create the main frame
MyFrame::MyFrame(const wxString& title)
       : wxFrame(NULL, wxID_ANY, title)
{   
    // Create menu bar
    wxMenu *fileMenu = new wxMenu;

    wxMenu *helpMenu = new wxMenu;
    helpMenu->Append(wxID_ABOUT, wxT("&About...\tF1"), wxT("Show about dialog"));
    fileMenu->Append(wxID_EXIT, wxT("E&xit\tAlt-X"), wxT("Quit this program"));

    // Now append the freshly created menu to the menu bar...
    wxMenuBar *menuBar = new wxMenuBar();
    menuBar->Append(fileMenu, wxT("&File"));
    menuBar->Append(helpMenu, wxT("&Help"));

    // ... and attach this menu bar to the frame
    SetMenuBar(menuBar);

    // Create a status bar just for fun
    CreateStatusBar(2);
    SetStatusText(wxT("Warning: Resize erases drawing."));

    // Create a panel to draw on
    // Note that the panel will be erased when the window is resized.
    wxPanel* panel = new wxPanel(this, wxID_ANY);
    // Listen to mouse move events on that panel
    panel->Connect( wxID_ANY, wxEVT_MOTION, wxMouseEventHandler(MyFrame::OnMotion));
}

要构建,我使用以下Makefile,但这对您不起作用,因为您可能没有macosx-app实用程序。请参阅Building a MacOSX application bundle的维基指南。

CC = g++ -m32

minimal: minimal.o
    $(CC) -o minimal minimal.o `wx-config --libs`
    macosx-app $@

minimal.o: minimal.cpp
    $(CC) `wx-config --cxxflags` -c minimal.cpp -o minimal.o

clean:
    rm -f *.o minimal