As 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 LINEinherit 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 !! p.make (x, y) extend (p) end invariant positive_width: width >= 0 end -- class LINE
Class POINT is simply defined as follows:
class POINTcreation 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") !! dc.make (Current) set_pen_width (1) !! 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) !! 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 !! 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_WINDOWinherit 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") !! dc.make (Current) set_pen_width (1) !! 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 !! 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) !! 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 !! 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 !! 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 !! 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
Here is the full text of MAIN_WINDOW (Personal version):
class MAIN_WINDOWinherit 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") !! dc.make (Current) set_pen_width (1) !! 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 !! 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) !! 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 !! 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 !! 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 !! 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