Пример кода для минимальной программы рисования (стиль MS Paint) - PullRequest
3 голосов
/ 14 августа 2010

Я хочу написать программу для рисования в стиле MS Paint.

На базовом уровне я должен рисовать точку на экране всякий раз, когда пользователь перетаскивает мышь.

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

К сожалению, у меня проблемы с моей структурой GUI (см. Предыдущий вопрос ), я не получаю сообщения о перемещении мыши достаточно часто. Я использую графический интерфейс wxWidgets и язык программирования Haskell.

Вопрос: Не могли бы вы дать мне пример кода , который реализует такую ​​минимальную процедуру рисования? Желательно, чтобы в вашем коде использовалось wxWidgets , но я также принимаю GTK + или Cocoa. Я не против любого языка программирования , если я могу легко установить его на MacOS X. Пожалуйста, включите весь проект , make-файлы и все, поскольку у меня, вероятно, нет большой опыт компиляции вашего языка.

В принципе, я хотел бы иметь небольшой пример, который показывает мне, как сделать это правильно в wxWidgets или другом каркасе GUI, чтобы я мог выяснить, почему моя комбинация Haskell и wxWidgets не дает приличной частоты перемещения мыши события.

Ответы [ 4 ]

4 голосов
/ 14 августа 2010

Для Какао Apple предоставляет пример с именем CIMicroPaint , хотя он немного сложен в том смысле, что он использует Core Image вместо Quartz 2D. Вот скриншот: CIMicroPaint скриншот http://i36.tinypic.com/29mm2vs.jpg

2 голосов
/ 16 марта 2012

Я знаю, что это старый вопрос, но тем не менее - для получения плавного рисования недостаточно просто поместить экземпляр вашей кисти в местоположение мыши, поскольку события ввода не опрашиваются нигде так быстро, какони должны для гладкого рисования.

Рисование линий - очень ограниченное решение, так как линии ... являются линиями, и для приложения для рисования вам нужно иметь возможность использовать пользовательские растровые кисти.

Решение простое, у вас естьчтобы интерполировать предыдущую и текущую позицию курсора, найдите линию между двумя точками и интерполируйте ее, добавив кисть для каждого пикселя между двумя точками.

Для моего решения я использовал 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-планшет, который довольно медленный и медленный, и работает очень хорошо.

1 голос
/ 15 августа 2010

Чтобы ответить на мой собственный вопрос, вот минимальный пример рисования на C ++ с использованием wxWidgets. В основном я собрал фрагменты из книги Кросс-платформенное программирование с помощью wxWidgets , которая доступна онлайн бесплатно.

Рисование максимально плавное, проблем с частотой событий мыши нет, как видно на скриншоте. Обратите внимание, что рисунок будет потерян при изменении размера окна. Пример рисования wxWidgets 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. Обратитесь к руководству вики по Сборка приложения MacOSX .

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
1 голос
/ 14 августа 2010

как и ваши глаза, курсор перемещается в прыжках, поэтому вам нужно будет рисовать линии между каждой точкой, в которой был записан курсор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...