【问题标题】:Example code for a minimal paint program (MS Paint style)最小绘图程序的示例代码(MS Paint 样式)
【发布时间】:2011-03-29 21:11:44
【问题描述】:

我想写一个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 的组合没有给出合适的鼠标移动频率事件。

【问题讨论】:

  • 我认为这个网站是用来提问和回答的,而不是 do-my-project-for-me。
  • 这不是我的项目问题,而是我的previous question 的后续问题。如果无法与工作示例进行比较,我很难确定我的鼠标移动事件频率非常低的问题。
  • 我怀疑它是否有帮助,但这在 Tcl/Tk 中是微不足道的。我花了几分钟用大约 20 行代码编写了一个简单的示例;不需要生成文件或其他任何东西。你对此感兴趣吗?
  • 很遗憾,Haskell 没有 Tcl/Tk 绑定。但你肯定会得到一些支持。 :-)
  • @Heinrich Apfelmus:一个快速的谷歌表明这是错误的。 一个绑定到 Tk 的 haskell:informatik.uni-bremen.de/htk 虽然,该页面说没有太多积极的开发。如果这只是一个无关紧要的教育练习。

标签: cocoa user-interface gtk wxwidgets paint


【解决方案1】:

对于 Cocoa,Apple 提供了一个名为 CIMicroPaint 的示例,尽管它使用 Core Image 而不是 Quartz 2D 有点复杂。这是一个屏幕截图:

【讨论】:

    【解决方案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 平板电脑上测试过它,这是一款非常缓慢且滞后的设备,并且运行良好。

    【讨论】:

      【解决方案3】:

      为了回答我自己的问题,这里有一个使用 wxWidgets 的 C++ 中的最小绘制示例。我主要是从Cross-Platform GUI Programming with wxWidgets这本书里组装的sn-ps,网上免费提供。

      绘图尽可能流畅,鼠标事件频率没有问题,从截图可以看出。请注意,当调整窗口大小时,绘图将会丢失。

      这是 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 的 wiki 指南。

      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
      

      【讨论】:

        【解决方案4】:

        就像您的眼睛一样,光标会跳跃移动,因此您需要在记录光标的每个点之间画线。

        【讨论】:

        • 我知道,但我仍然需要适当频率的鼠标移动事件或lines become jagged
        • @Heinrich Apfelmus:如果您需要更流畅的鼠标指针移动,您可以更改操作系统(或桌面环境)的设置。
        • PC2st:更改鼠标跟踪速度不会影响事件之间时间的频率,只会影响空间中的间隔(在高鼠标-移动速度)。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-01
        • 2020-12-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多