|
Step 6: Repainting a windowAs you have probably noticed, the graphics and text you draw in a window using device context functions (like line_to or text_out) disappear when you resize or uncover the window. Windows does not save the graphics that you draw in the device context, the application is in charge to refresh the window when it is necessary. In this step you will learn how to do that. When the user of your application resizes or uncovers a window, it requires updating, or painting. WEL automatically calls the on_paint procedure (from WEL_COMPOSITE_WINDOW) when the window needs to be painted. Procedure on_paint is where you write the code to paint the contents of the window. There is one major difference between drawing graphics in the on_paint procedure and at other times, such as in response to mouse actions. The device context to be used for painting is passed in the paint_dc parameter, so your program does not need to get and release it. You will, however, need to select your drawing tools into the paint_dc. To paint a window's contents, you are going to replay the actions that led to the original drawing on dc, but use paint_dc instead. But first, you need to store the graphic as objects, so you can paint them in the on_paint procedure. Let's say that the window's contents is a set of lines, and each line is a set of points with a width. Then, you can simply define a line as follows: class LINE inherit LINKED_LIST [POINT] creation make feature -- Access width: INTEGER -- Width of the line feature -- Element change set_width (a_width: INTEGER) is -- Set width with a_width. require positive_width: a_width >= 0 do width := a_width ensure width_set: width = a_width end add (x, y: INTEGER) is -- Add a point specified by x and y. local p: POINT do create p.make (x, y) extend (p) end invariant positive_width: width >= 0 end -- class LINE Class POINT is simply defined as follows: class POINT creation make feature -- Initialization make (a_x, a_y: INTEGER) is -- Make a point with a_x and a_y. do x := a_x y := a_y ensure x_set: x = a_x y_set: y = a_y end feature -- Access x: INTEGER -- x position y: INTEGER -- y position end -- class POINT Using class LINE, the basic idea consists of saving mouse movements while the user draws. Then, you will use these data in the on_paint procedure to redraw window's contents. First, you need to add the following attributes in class MAIN_WINDOW. lines: LINKED_LIST [LINE] -- All lines drawn by the user current_line: LINE -- Line currently drawn by the user Attribute lines needs to be created in the make routine as follows: make is -- Make the main window. do make_top ("My application") create dc.make (Current) set_pen_width (1) create lines.make end And finally, you have to change on_left_button_down and on_mouse_move to store the points in lines. on_left_button_down (keys, x_pos, y_pos: INTEGER) is -- Initiate the drawing process. do if not button_down then button_down := true dc.get dc.move_to (x_pos, y_pos) dc.select_pen (pen) create current_line.make current_line.set_width (pen.width) lines.extend (current_line) current_line.add (x_pos, y_pos) end end on_mouse_move (keys, x_pos, y_pos: INTEGER) is -- Connect the points to make lines. do if button_down then dc.line_to (x_pos, y_pos) current_line.add (x_pos, y_pos) end end At this point, lines has all the information needed to redraw the window's contents. Basically, you just need to redefine on_paint and iterate over the list to draw the lines as follows: on_paint (paint_dc: WEL_PAINT_DC; invalid_rect: WEL_RECT) is -- Paint the lines. local a_line: LINE a_pen: WEL_PEN first_point: BOOLEAN do from lines.start until lines.off loop from first_point := true a_line := lines.item a_line.start create a_pen.make_solid (a_line.width, black) paint_dc.select_pen (a_pen) until a_line.off loop if first_point then first_point := false paint_dc.move_to (a_line.item.x, a_line.item.y) else paint_dc.line_to (a_line.item.x, a_line.item.y) end a_line.forth end lines.forth end end Now, if you minimize and restore the window, you will see that window's contents is restored. Here is the full text of MAIN_WINDOW (Professional version): class MAIN_WINDOW inherit WEL_FRAME_WINDOW redefine on_left_button_down, on_left_button_up, on_right_button_down, on_mouse_move, on_paint, closeable end WEL_STANDARD_COLORS export {NONE} all end creation make feature {NONE} -- Initialization make is -- Make the main window. do make_top ("My application") create dc.make (Current) set_pen_width (1) create lines.make end feature -- Access dc: WEL_CLIENT_DC -- Device context associated to the current -- client window button_down: BOOLEAN -- Is the left mouse button down? pen: WEL_PEN -- Pen currently selected in dc line_thickness_dialog: LINE_THICKNESS_DIALOG -- Dialog box to change line thickness lines: LINKED_LIST [LINE] -- All lines drawn by the user current_line: LINE -- Line currently drawn by the user feature -- Element change set_pen_width (new_width: INTEGER) is -- Set pen width with new_width. do create pen.make_solid (new_width, black) end feature {NONE} -- Implementation on_left_button_down (keys, x_pos, y_pos: INTEGER) is -- Initiate the drawing process. do if not button_down then button_down := true dc.get dc.move_to (x_pos, y_pos) dc.select_pen (pen) create current_line.make current_line.set_width (pen.width) lines.extend (current_line) current_line.add (x_pos, y_pos) end end on_mouse_move (keys, x_pos, y_pos: INTEGER) is -- Connect the points to make lines. do if button_down then dc.line_to (x_pos, y_pos) current_line.add (x_pos, y_pos) end end on_left_button_up (keys, x_pos, y_pos: INTEGER) is -- Terminate the drawing process. do if button_down then button_down := false dc.release end end on_right_button_down (keys, x_pos, y_pos: INTEGER) is -- Bring up line_thickness_dialog and set the -- new pen width. do if line_thickness_dialog = void then create line_thickness_dialog.make (Current) end line_thickness_dialog.activate if line_thickness_dialog.ok_pushed then set_pen_width (line_thickness_dialog.pen_width) end end on_paint (paint_dc: WEL_PAINT_DC; invalid_rect: WEL_RECT) is -- Paint the lines. local a_line: LINE a_pen: WEL_PEN first_point: BOOLEAN do from lines.start until lines.off loop from first_point := true a_line := lines.item a_line.start create a_pen.make_solid (a_line.width, black) paint_dc.select_pen (a_pen) until a_line.off loop if first_point then first_point := false paint_dc.move_to (a_line.item.x, a_line.item.y) else paint_dc.line_to (a_line.item.x, a_line.item.y) end a_line.forth end lines.forth end end closeable: BOOLEAN is -- Does the user want to quit? local msgBox: WEL_MSG_BOX do create msgBox.make msgBox.question_message_box (Current, "Do you want to quit?", "Quit") Result := msgBox.message_box_result = Mb_ok end end -- class MAIN_WINDOWHere is the full text of MAIN_WINDOW (Personal version): class MAIN_WINDOW inherit WEL_FRAME_WINDOW redefine on_left_button_down, on_left_button_up, on_right_button_down, on_mouse_move, on_paint, closeable end WEL_STANDARD_COLORS export {NONE} all end creation make feature {NONE} -- Initialization make is -- Make the main window. do make_top ("My application") create dc.make (Current) set_pen_width (1) create lines.make end feature -- Access dc: WEL_CLIENT_DC -- Device context associated to the current -- client window button_down: BOOLEAN -- Is the left mouse button down? pen: WEL_PEN -- Pen currently selected in dc line_thickness_window: LINE_THICKNESS_WINDOW -- Window to change line thickness lines: LINKED_LIST [LINE] -- All lines drawn by the user current_line: LINE -- Line currently drawn by the user feature -- Element change set_pen_width (new_width: INTEGER) is -- Set pen width with new_width. do create pen.make_solid (new_width, black) end feature {NONE} -- Implementation on_left_button_down (keys, x_pos, y_pos: INTEGER) is -- Initiate the drawing process. do if not button_down then button_down := true dc.get dc.move_to (x_pos, y_pos) dc.select_pen (pen) create current_line.make current_line.set_width (pen.width) lines.extend (current_line) current_line.add (x_pos, y_pos) end end on_mouse_move (keys, x_pos, y_pos: INTEGER) is -- Connect the points to make lines. do if button_down then dc.line_to (x_pos, y_pos) current_line.add (x_pos, y_pos) end end on_left_button_up (keys, x_pos, y_pos: INTEGER) is -- Terminate the drawing process. do if button_down then button_down := false dc.release end end on_right_button_down (keys, x_pos, y_pos: INTEGER) is -- Bring up line_thickness_window and set the -- new pen width. do if line_thickness_window = void then create line_thickness_window.make (Current) end line_thickness_window.activate end on_paint (paint_dc: WEL_PAINT_DC; invalid_rect: WEL_RECT) is -- Paint the lines. local a_line: LINE a_pen: WEL_PEN first_point: BOOLEAN do from lines.start until lines.off loop from first_point := true a_line := lines.item a_line.start create a_pen.make_solid (a_line.width, black) paint_dc.select_pen (a_pen) until a_line.off loop if first_point then first_point := false paint_dc.move_to (a_line.item.x, a_line.item.y) else paint_dc.line_to (a_line.item.x, a_line.item.y) end a_line.forth end lines.forth end end closeable: BOOLEAN is -- Does the user want to quit? local msgBox: WEL_MSG_BOX do create msgBox.make msgBox.question_message_box (Current, "Do you want to quit?", "Quit") Result := msgBox.message_box_result = Mb_ok end end -- class MAIN_WINDOW |