Graphic board program

Source: Internet
Author: User

 

I have been doing some image processing recently.

Part 1:

Make a picture boardProgramMspaint in Windows
First of all, I want to think about how to implement the basic functions of the pencil, draw a line, draw a circle, and draw a box. In order to highlight the differences, I want to make a function to adjust the size of the image by dragging.
To redefine the image, you need to save the metadata of the image so that you can adjust the image in the future.
Draw a line, draw a circle, draw a circle, and call all words in. Net graphic, and then re-draw in onpaint.
I understand the principle and do not want to implement it myself. I wrote a line in winfrom.ArticleIt's just that we don't have to create any more wheels.

First, let's get a tool Switching Effect on the toolbar. Drag a menustrip control and add five menu items:


Write the code of the itemclicked event of menustrip. Note that it is not the Click Event of the menu item:

 
// Tool switching effect private void menustripincluitemclicked (Object sender, toolstripitemclickedeventargs e) {for (INT I = 0; I <menustrip1.items. count; I ++) {menustrip1.items [I]. backcolor = color. fromname ("control");} e. clickeditem. backcolor = color. green ;}

Then, declare five enumeration tools and click the menu item to switch between them:

Private void draw line toolstripmenuitem_click (Object sender, eventargs e) {type = tooltype. line;} private void pencil toolstripmenuitem_click (Object sender, eventargs e) {type = tooltype. penpencil;} tooltype type; Enum tooltype {Line, penpencil, REC}

Then there is the painting process. You can't draw the metadata directly on the form. Do you need to save the metadata? For a line segment, you can use ilist <point> to use the graphicpath rectangle with a pencil. <rectangle>
When painting, press the mouse, drag, and release to add the image to the background. The image is reproduced when the onpaint event occurs.
Below are someCodeI have said that wire and frame painting is a one-sentence call in. net. The Pencil tool is slightly more complex:

Private void form1_paint (Object sender, painteventargs e) {// For (INT I = 0; I <line. count; I + = 1) // {// if (I> = line. count-1) // break; // E. graphics. drawline (pens. red, line [I], line [I + 1]); //} For (INT I = 0; I <lines. count; I + = 2) {if (I> = lines. count-1) break; E. graphics. drawline (pens. red, lines [I], lines [I + 1]);} foreach (rectangle REC in RECs) {e. graphics. drawrectangle (pens. green, REC) ;}} private void form=mousemove (Object sender, mouseeventargs e) {// line. add (E. location); invalidate ();} ilist <point> lines = new list <point> (); ilist <rectangle> RECs = new list <rectangle> (); private void form=mousedown (Object sender, mouseeventargs e) {startmouse = E. location;} Point startmouse; private void form=mouseup (Object sender, mouseeventargs e) {Switch (type) {Case tooltype. line: {lines. add (startmouse); lines. add (E. location); break;} case tooltype. REC: {Recs. add (New rectangle (startmouse, new size (E. location. x-startmouse. x, E. location. y-startmouse. y); break;} invalidate ();}

In addition, the rectangle only deals with the case from the top left to the bottom right. In other cases, the function is implemented in the complete code.
There is also why there is no "instant effect", that is, the drag effect of the broken line and frame. Add these two sentences to onpaint:

 
If (! Mousedown) return; If (type = tooltype. line) E. graphics. drawline (pens. red, startmouse, tmpmouse); If (type = tooltype. REC) E. graphics. drawrectangle (pens. green, new rectangle (startmouse, new size (tmpmouse. x-startmouse. x, tmpmouse. y-startmouse. Y )));

Of course, you have to add a mousedown bool variable to make it false when the mouse is pressed to true, and assign a value to the tmpmouse when the mouse moves.
Download all the above source code and click here
Dangdang now has a picture board. You can use it ;)


What about the drag function? This is actually very simple. If the current object selection tool (the last button) takes that coordinate to all objects when the mouse is pressed to detect the selected image if there is a matching one.
Check the method. check whether a point is in the source code of the second part in my article that draws a straight line on a broken line. It's easier to detect rectangles.
When you move the mouse, check whether the current object is detected and selected. If you drag the object, the drag process does not simply change the coordinates of the current object. do not tell me If offset is changed based on the current mouse position.
These are all in the source code of the second part.

Part 2:

Isn't the program finished? Why do we have to go through the second part? after reading the second part, we can see that the second part of the code is better, and all the code in the second part is rewritten.
The above is still not a good structure. In order to make the extended program structure including future functions clearer, we have to design it in an object-oriented way to logically separate the data model code, define the function category
Imagine drawing on the blackboard when I was in the middle school ry class. For example, this is a system. It has a blackboard (board class). This object is not the bearer body of all images, including the drawing currently being painted by the background color chalk,
The image is a predefined shape with a triangle rectangle (Circle Line pencel square)
However, they all have the same features, such as the color fill color of the line at the position on the blackboard. They share the same base class (SHAPE). This can be achieved through inheritance:

To review the most basic inheritance and virtual method implementation:

Class program {static void main (string [] ARGs) {ilist <father> fathers = new list <father> (); fathers. add (new son (); fathers. add (new son (); fathers [0]. method (); fathers [0]. method2 () ;}} class father {Public Virtual void method () {console. writeline ("Father's method");} Public Virtual void method2 () {console. writeline ("Father's method2");} class son: Father {public override void method () {console. writeline ("Son's method"); // base. method ();}}

Output:
Son's Method
Father's method2
In the end, virtual and override are the essence of object-oriented, and subclass realizes that the subclass of the called subclass does not call the parent class. This mode is widely used in MFC including VC ++.
The original transition from C to C ++ did not have so many messy object-oriented design theories, but only had such a concept.

This is a graphical representation and method implementation part of the Code. The purpose of doing so is to define the data model for extension. For example, if I do not need to draw a rectangle in the future, I can delete the class of the rectangle.
If you want to draw a star, you can add a class that inherits the shape of the star. For example, each image has the same background color. You can define showbackground () in shape for each inherited object to call.
Instead of implementing this method all over again.

# Region graphics base class public class shape {public rectangle region; // The image size and position public int linealpha = 100; // transparency public int layer = 1; // stack position public pen line = new pen (color. red, 1); // The line string attribute public color bgcolor = color. lavender; // background color public int bgcoloralpha = 50; Public point mousestart = point. empty; // start point of the mouse public point mouseend = point. empty; // The mouse End Point Public bool selected = false; Public shape () {} public shape (color _ Linecolor, point _ mousestart) {Line. color = _ linecolor; this. region = new rectangle (); region. location = _ mousestart; region. width = 0; region. height = 0;} // draw (actually data update) Public Virtual void draw (point P) {} Public Virtual void move (int x, int y) // move {region according to the offset. location. offset (x, y);} Public Virtual bool select (point P) {return false;} Public Virtual void show (Graphics handle) // display {handle. Drawrectangle (line, this. region) ;}# endregion # region line segment public class line: Shape {// initialize a line segment public line (point _ start, point _ end) {This. mousestart = _ start; this. mouseend = _ end; region. X = mouseend. x> mousestart. x? Mousestart. X: mousestart. X-(mousestart. X-mouseend. X); region. Y = mouseend. Y> mousestart. Y? Mousestart. y: mousestart. y-(mousestart. y-mouseend. y); region. width = math. ABS (mousestart. x-mouseend. x); region. height = math. ABS (mousestart. y-mouseend. y);} public line () {}// initialize a line segment with a single point (the same coordinate between the start point and the end point cannot be called a line segment accurately. It should be a point) public line (point _ start) {Line. color = color. red; this. mousestart = _ start; this. mouseend = point. empty; region. X = mousestart. x; region. y = mousestart. y; region. width = 0; Region. height = 0;} // draw (update data for two points) Public override void draw (point P) {If (mousestart = point. empty) {This. region = new rectangle (); region. location = P; region. width = 0; region. height = 0;} else // If (mouseend = point. empty) {mouseend = P; region. X = mouseend. x> mousestart. x? Mousestart. X: mousestart. X-(mousestart. X-mouseend. X); region. Y = mouseend. Y> mousestart. Y? Mousestart. y: mousestart. y-(mousestart. y-mouseend. y); region. width = math. ABS (mousestart. x-mouseend. x); region. height = math. ABS (mousestart. y-mouseend. y) ;}}// display the current instance (draw a straight line based on the starting coordinate) Public override void show (Graphics handle) {handle. drawline (line, mousestart, mouseend);} // move public override void move (int x, int y) {mousestart. offset (x, y); mouseend. offset (x, y); region. location. offset (x, y);} public override bool select (point mouse) {util u = new util (); If (U. linedetector (mouse, mousestart, mouseend) {selected = true; return true;} selected = false; return false ;}# endregion

 
Computer-related things, especially program development. Some things need to be clear about the principle and understand everything, don't just look at some of the tools on the surface. This is a bit of a technology discovery training institution.

I want to use the mouse to follow the drawrectangle so that I can draw the mouse handwriting. Finally, I found that the mouse could not keep up with the drawing,
I have never read other people's code before. I think it should be done like this.
The original Pencil tool code...

 
Private void form=mousemove (Object sender, mouseeventargs e) {graphics G = graphics. fromhwnd (this. handle); G. drawrectangle (pens. red, new rectangle (E. location, new size (2, 2 )));}

 
This looks a bit like an eraser.
Items searched on Baidu are useless. The reason is that the mouse does not capture the point. In fact, the bottom layer of every coordinate system of the mouse can only catch up with the painting speed,
Move the mouse slowly. Fortunately, you said that moving is faster, and the constant drawrectangle is constantly charging system resources. How can it keep up with the possibility that it is also based on CPU time slice? So some of them are missing.
There may be some principles and things that you will probably understand, but you have to think about it. Otherwise, what program development should you do? Now, when doing program design, it is no longer necessary for those who are careful and careful about the C language.
One hard day, I tried to study those mathematical algorithms. Master Tan's "C programming" is a good book that is difficult but not too difficult to understand.
Later, I knew what graphicspath is used for listening to the name. Then I continued to use graphicspath. addline to connect the mouse-moving path to graphicspath.
It was exactly the same as the graphic board in Windows when I tried it. I think this method is also used in it. Note that graphicpath is not used in the Pencil tool code.

Private void form1_paint (Object sender, painteventargs e) {for (INT I = 0; I <line. count; I + = 1) {if (I> = line. count-1) break; E. graphics. drawline (pens. red, line [I], line [I + 1]) ;}} private void form=mousemove (Object sender, mouseeventargs e) {Line. add (E. location); invalidate ();} ilist <point> line = new list <point> ();

 

If I + = 2 in a loop, it turns into a dotted line, and the larger the value, the more fierce and interesting it is ;). In fact, polygon can also be used in this way to understand the point values of two groups in the array.

Don't forget to add double buffer code

 
This. setstyle (controlstyles. userpaint, true); this. setstyle (controlstyles. allpaintinginwmpaint, true); // disable background erasure. This. setstyle (controlstyles. doublebuffer, true );

It seems complicated to clear the specified part of the image to reach the effect of the eraser. In fact, you can't think of it in turn. The eraser is a paint brush with a special background color.

The concept of onpainting is not included in winfrom in MFC. This is an important concept of Windows forms that must be understood.
In the original example, E. graphics has previously seen graphics G = graphics. fromhandle (this. Handle) moving over the Internet,
This time, E. graphics is used directly in onpaint. It can be seen that the onpaint function directly takes over the underlying windwos re-painting message, which has a different effect. It's convenient to have. NET and winform.
Everything is programmed based on the hosting platform. We don't have to process underlying Windows messages, so we don't understand the principle.

In addition, the efficiency in the Code for drawing or instant effects is very important, because the code that is re-painted may be run countless times every second.
Code needs to be optimized, including various condition judgments, so as to improve efficiency. One way is to ensure that the Code will be executed only when it is really needed. The bad code in the school should not be integrated into it, but it will all come from the bad code. bei.
The design of the program is also very important. I never make a mess in the winform code. winfrom is only responsible for calling which class inherits which class program structure is neat and clean.

It's useless again.

Finally, the source code of the final program of the graphic board is hitting here for fear that some friends may not be able to run it. compiled in net2.0 mode. Here is a learning point. Don't hide the whole thing. Don't bother with the source code.
If your code is useful, leave a name.

There are still many imperfections in the program, such as the judgment and deformation of the elliptical area. The drag function of the ellipse has not implemented any other functions.
In addition, when dragging, the image grabbing's tolerance is 5 pixels. There is no color or cursor change in the Process of capturing and dragging a line segment. Pay attention to shoes, so that the feature is not implemented.

In fact, it is not difficult to draw a picture board. Even if you want to make a vector, you can perform post-processing, you can drag the deformation of the multi-layer, even if you do Photoshop, it is not very difficult, you can see in in the article "cropping effect", I have implemented the Alpha transparent effect rounded corner rectangle and so on. This is not actually image processing. Special theories are required for specialized image processing.AlgorithmI admit that there is still a lack of High-data plane ry and I still need to study hard.

It's time to stay up late and write this ghost stuff over five minutes.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.