2010-08-14 1 views
3

Я хочу написать программу рисования в стиле MS 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. Пожалуйста, включите весь проект, make-файлы и все, так как у меня, вероятно, нет большого опыта в составлении вашего языка.

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

+0

Я думаю, что этот сайт предназначен для вопросов и ответов, а не для моего проекта для меня. –

+0

Вопрос не о моем проекте для меня, это продолжение моего [предыдущего вопроса] (http://stackoverflow.com/questions/3347483/writing-a-paint-program-a-la -ms-краска, как-к-интерполировать-между мышиным въезду накануне). Мне сложно определить мою проблему получения действительно низкой частоты событий перемещения мыши, не имея возможности сравнить с рабочим примером. –

+0

Я сомневаюсь, что это помогает, но это тривиально в Tcl/Tk. Мне потребовалось пару минут, чтобы составить простой пример примерно в 20 строках кода; никакие make-файлы или что-либо еще не требуется. Вас это интересует? –

ответ

1

Чтобы ответить на мой собственный вопрос, вот минимальный пример рисования на C++ с использованием wxWidgets. Я в основном собрал фрагменты из книги 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 [email protected] 

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

clean: 
    rm -f *.o minimal 
1

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

+0

Я знаю, но мне все еще нужна приличная частота событий перемещения мыши или [линии становятся зубчатыми] (http://stackoverflow.com/questions/3347483/writing-a-paint-program-a-la-ms-paint -как к Interpolate-между мышиным въезду накануне). –

+0

@Heinrich Apfelmus: Если вам нужны более плавные перемещения указателя мыши, вы можете изменить настройки своей ОС (или среды рабочего стола). –

+0

PC2st: Изменение скорости отслеживания мыши не влияет на частоту в * время * между событиями, а только интервалы в * пространстве * (при высокой скорости перемещения мыши). –

2

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

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

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

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

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