Jump to content

Moving line in graphic causes flicker problem


matrix200
 Share

Recommended Posts

Hi all

I am writing ups monitoring application which is going to be knutclient windows clone

http://www.alo.cz/knutclient/

My problem is that when i try to refresh the analogue clocks state by moving the needle sometimes (usually after a while) I am getting a flicker.

When I was using $GUI_GR_REFRESH it was flickering the whole window.

Now I have limited that only to the area of the clock itself.

Still it is very annoying.

Here is a snippet of my code to show the problem

#include <GUIConstants.au3>
Global $gui = 0
Global $num = 265
Global $needle1 = 0
Global $inputv = 0
Global $gray  = "0xD4D0C8"
Func Update()

    $num  = $num + 1
    if $num = 271 Then
        $num = 210
    EndIf
    UpdateValue(136 , 70 , $needle1 , String($num) , $inputv )
    
EndFunc

Func ForceRefresh($hWnd, $rRect=0, $bErase=0)
  Local $pRect, $aResult

  if $rRect <> 0 then $pRect = DllStructGetPtr($rRect)
  $aResult = DllCall("User32.dll", "int", "InvalidateRect", "hwnd", $hWnd, "ptr", $pRect, "int", 0)
  Return ($aResult[0] <> 0)
EndFunc


Func UpdateValue($left , $top , byref $needle , $value , $label , $min = 170, $max = 270)
    
;GUICtrlSendMsg($gui,0x000F,FALSE , 0)
    $oldval = Round (GuiCtrlRead($label))
;ConsoleWrite($oldval)
    if $oldval == Round($value) Then
        Return
    EndIf 
;GuiCtrlDelete($needle)
    GuiCtrlSetData($label , $value )
    $value = Round($value )
    if $value < $min Then
        $value = $min
    EndIf
    if $value > $max Then
        $value = $max
    EndIf
    $oldneedle = ($oldval - $min) / ( ($max - $min ) / 100 )
;ConsoleWrite($oldneedle)
    GUICtrlSetGraphic($needle,$GUI_GR_MOVE, 10 + $oldneedle , 10  )
    GUICtrlSetGraphic($needle,$GUI_GR_PENSIZE, 2)
    GUICtrlSetGraphic($needle,$GUI_GR_COLOR, 0x00ffff)
    GUICtrlSetGraphic($needle, $GUI_GR_LINE, 60  , 70  )
    GUICtrlSetGraphic($needle,$GUI_GR_CLOSE)
;$needle = GUICtrlCreateGraphic(10 + $left ,35 + $top , 120 , 80 )
    $setneedle =($value - $min)/ ( ($max - $min ) / 100 )
    GUICtrlSetGraphic($needle,$GUI_GR_MOVE, 10 + $setneedle , 10  )
    GUICtrlSetGraphic($needle,$GUI_GR_PENSIZE, 2)
    GUICtrlSetGraphic($needle,$GUI_GR_COLOR, 0x000000)
    GUICtrlSetGraphic($needle, $GUI_GR_LINE, 60  , 70  )
    GUICtrlSetGraphic($needle,$GUI_GR_CLOSE)
    $struct = DllStructCreate("long;long;long;long")
    
    DllStructSetData($struct , 1 , 10 )
    DllStructSetData($struct , 2 , 10)
    DllStructSetData($struct , 3 , 110 )
    DllStructSetData($struct , 4 , 70 ) 
;GUICtrlSendMsg( $gui,0x000F,TRUE , 0)
    DllStructSetData($struct , 1 , Int($left)+ 10 )
    DllStructSetData($struct , 2 , Int($top) + 40 )
    DllStructSetData($struct , 3 , Int($left) + 110 )
    DllStructSetData($struct , 4 , Int($top) + 80 )
    ForceRefresh($gui , $struct , false )
    
EndFunc

Func DrawDial($left , $top , $basescale , $title , $units , ByRef $value , ByRef $needle , $scale = 1 , $leftG = 20, $rightG = 70 , $bkColor = 0xD4D0C8)
    
    $group = GUICtrlCreateGroup( $title , $left , $top , 150 ,120 ,Bitor( 0,$BS_CENTER) )
    GUICtrlSetBkColor(-1,0x00ffff)
    GuiCtrlCreateGraphic($left , $top , 150 , 120 )
    GUICtrlSetBkColor(-1,0x00ffff)
    for $x = 0 to 100 step 10
        if $x > 0 Then
            $y = 1
        Else
            $y = 0
        endif
        if StringinStr($x / 20,".") = 0 Then
            GUICtrlCreateLabel("",$x * 1.2 + $left + 10 , 15 + $top , 1 , 15 , $SS_BLACKRECT)
            GUICtrlSetBkColor(-1, 0x00ffff)
            if $x < 100 Then
                $test = GUICtrlCreateLabel("",$x * 1.2 +$left + 11,15 + $top , 11 , 5 , 0 )
                GUICtrlSetBkColor(-1, 0x00ffff)
                if $x < $rightG and $x > $leftG then
                    GUICtrlSetBkColor($test , 0x00ff00)
                Else
                    GUICtrlSetBkColor($test , 0xff0000)
                EndIf
            EndIf
            $scalevalue = $basescale + $x / $scale
            if ($x == 0 and $scalevalue > 99 ) or ( $scalevalue <100 and $scalevalue > 9 ) then
                GUICtrlCreateLabel( $scalevalue , $x * 1.2+ $left + 5, 25 + $top )
                GUICtrlSetBkColor(-1, 0x00ffff)
            Else 
                if $scalevalue < 10 Then
                    GUICtrlCreateLabel($scalevalue , $x * 1.2 + $left + 8, 25 + $top )
                    GUICtrlSetBkColor(-1, 0x00ffff)
                Else
                    GUICtrlCreateLabel($scalevalue , $x * 1.2 + $left, 25 + $top )
                    GUICtrlSetBkColor(-1, 0x00ffff)
                EndIf
            EndIf
            GUICtrlSetFont(-1,7)
        Else
            GUICtrlCreateLabel("",$x * 1.2 + $left + 10 , 15 + $top , 1 , 5 , $SS_BLACKRECT )
            GUICtrlSetBkColor(-1, 0x00ffff)
            $test = GUICtrlCreateLabel("", $x *1.2 +$left + 11 ,15 + $top , 11 , 5 , 0 )
            GUICtrlSetBkColor(-1, 0x00ffff)
            if $x < $rightG and $x > $leftG then
                GUICtrlSetBkColor($test , 0x00ff00)
            Else
                GUICtrlSetBkColor($test , 0xff0000)
            EndIf
        EndIf       
    Next    
    $value = GUICtrlCreateLabel($value, 10 + $left ,100 + $top , 40 , 15 )
    GUICtrlSetBkColor(-1, 0x00ffff)
    $label2 = GUICtrlCreateLabel($units , 125 + $left ,100 + $top , 20 , 15 )
    GUICtrlSetBkColor(-1, 0x00ffff)
    $needle = GUICtrlCreateGraphic(10 + $left ,35 + $top , 115 , 80 )
    GUICtrlSetBkColor(-1, 0x00ffff) 
EndFunc

Func skipBg($hWndGUI, $MsgID)
    
    Return

EndFunc

$inputv ="265"
$needle1  = 0
$voltage ="V"
$gui = GUICreate("UPS Monitor", 608 + 25, 338, -1 , -1)
DrawDial(136 , 70 , 170 , "Input Voltage" , $voltage , $inputv , $needle1 , 1)
;GUIRegisterMsg ( 0x0014, "skipBg" )
AdlibEnable("Update",1000)
GUISetState(@SW_SHOW)

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd
Link to comment
Share on other sites

Thanks for advice Zedna , but I have already tried that and sure enough the second the UNLOCK is executed the gui is redrawn and I get my flicker again.

The thing is it is not flickering on every refresh , only from time to time .

The longer the program runs the more flickering it gets and I start seeing remnants of the older arrows that were supposed to be deleted

a long time ago.

I also tried earlier to delete/recreate the graphic control , but that causes flicker all the time.

Could I somehow force the application to redraw only certain regions on the screen and NEVER redraw anything else?

Or maybe there is a way not to use the graphic at all to draw the arrow pointing to a value at my clocks?

Link to comment
Share on other sites

Or maybe there is a way not to use the graphic at all to draw the arrow pointing to a value at my clocks?

You can use Window API: LineTo, MoveTo, ... and then use

GUIRegisterMsg($WM_PAINT, 'MY_WM_PAINT')

look at BlackJack antiflicker methods

also look at my Radar.au3 - function MalujKriz() it's in my signature.

Link to comment
Share on other sites

Regarding BlackJack , Is that right that the main problem there was redrawing images?

I see what he did is simply inject some code to repaint the cards before calling to default WM_PAINT handler.

I don't see how that can help me since I am not using anything like card.dll in my program.

Regarding your code in Radar I tried to make it work with my program , but wasn't able to see any arrows at all (nothing is redrawn at all).

Here is the code I put instead of my update

$handle = ControlGetHandle($gui,"",$needle1)
    $user_dll = DllOpen("user32.dll")
    $gdi_dll = DllOpen("gdi32.dll")
    $l_hdc = DLLCall($user_dll,"int","GetDC","hwnd",$needle1)
    $pen = DLLCall($gdi_dll,"int","CreatePen","int",0,"int",2,"int",0xFF)
    $obj_orig = DLLCall($gdi_dll,"int","SelectObject","int",$l_hdc[0],"int",$pen[0])
    DLLCall($gdi_dll,"int","MoveToEx","int",$l_hdc[0],"int",10 + $oldneedle,"int",10,"int",0)
    DLLCall($gdi_dll,"int","LineTo","int",$l_hdc[0],"int",60,"int",70)
    DLLCall($gdi_dll,"int","SelectObject","int",$l_hdc[0],"int",$obj_orig[0])
    DLLCall($gdi_dll,"int","DeleteObject","int",$pen[0])
    $l_hdc = DLLCall($user_dll,"int","ReleaseDC","hwnd",$handle,"int",$l_hdc[0])
    DllClose($gdi_dll)
    DllClose($user_dll)

What am I doing wrong here?

Another interesting thing I noticed , when I added back the invalidate_rectangle call I saw occasional flicker again.

I am still using guictrlcreategraphic even though without its drawing functions , could it be the reason for the flicker?

In that case what kind of control I should choose?

Edited by matrix200
Link to comment
Share on other sites

Just an update Zedna.

I would like to thank you for the great help.

Your idea of using windows api works great!

The flicker is pretty much gone now.

Again thanks a lot for your help.

I am going to publish the whole program as I perfect it a little bit.

As far as I know it is first NUT ups windows gui client so I hope people are going to be interested ;)

Edited by matrix200
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...