我想以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的组合不能提供合适的鼠标移动频率事件
答案 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