WEL TUTORIAL 

Step 6: Repainting a window

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
	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 !! 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")
			!! 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_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") !! 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_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") !! 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


Previous Table of Contents Next