Topic: On AppGraphics basics

Hi jeff,

I am a novice in programming world.

I made a window having a few menuitems. By clicking a menuitem I open another window.
When I close the second window by clicking the close button at the top-right corner of the window, both windows close.
How can I make the first window keep open in this case?

Another problem is that while the second window is open I cannot use the first window.
How can I use both windows as I want?

Thanks in advance for your kind help.

sbhan

Re: On AppGraphics basics

sbhan,

When you create the new window, you need to make sure that the optional argument closeflag is set to .FALSE. or closing a window will subsequently end your program. 

You can continue to use both windows by using the setcurrentwindow.  To access your earlier window, call:

call setcurrentwindow(first_id)

and your subsequent calls for drawing, etc. will affect your original window.

Hopefully the above makes sense.

Jeff Armstrong
Approximatrix, LLC

Re: On AppGraphics basics

Jeff,

When two windows are open at the same time and the 2nd window has a closeflag of .FALSE., can the 2nd window be subsequently closed without ending the program (closing both windows)?

Any update on 'possible bug in Appgraphics' request regarding the ProgressBar iterative loop issue discussed previously in another forum.

Also is the fixed enablemenuitem() issue available in the current release of SF?  I can't seem to get it to work for submenu items in the main window at start up.

Thanks,
Frank

Re: On AppGraphics basics

drfrank wrote:

When two windows are open at the same time and the 2nd window has a closeflag of .FALSE., can the 2nd window be subsequently closed without ending the program (closing both windows)?

Yes, this should work fine.  If this isn't the case, it would be a bug.

drfrank wrote:

Any update on 'possible bug in Appgraphics' request regarding the ProgressBar iterative loop issue discussed previously in another forum.

Not yet.  I haven't looked into that one in detail yet.

drfrank wrote:

Also is the fixed enablemenuitem() issue available in the current release of SF?  I can't seem to get it to work for submenu items in the main window at start up.

This bug is fixed in our development version.  It will work fine when Simply Fortran 2.24 is released.

Jeff Armstrong
Approximatrix, LLC

Re: On AppGraphics basics

Hi Jeff,

First, I must admit that I don't fully understand the workings (logical order) of AppGraphics.  However, I've modified your Resize routine to display a 2nd window 'Splash screen' with a timer and the closeflag=.true. and a third window with the closeflag=.false.

In addition, I've added new FILE menu options to display a new window and to close a window. However, I'm still having trouble trying to close only the child windows while still displaying the main window.

When I try and close a window SF crashing with an error message.

If you have a chance, please take a look and see if this is a result of a bug or only my lack of knowledge.

The complete listing of your revised resize routine is attached below...

Thanks,
Frank

!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
program resizing
use appgraphics
implicit none

    integer::myscreen
    integer::mybutton
    integer, volatile::task

    integer, parameter::task_quit=0
    integer, parameter::task_open=1
    integer, parameter::task_run=2
    integer::run_item

    !--------------Added-------------------------------------\/
    integer, parameter::task_win=3
    integer, parameter::task_close=4
    integer         :: root_menu, file_menu, item_temp, win_menu, itr
    character(2)    :: CRLF
    character(512)  :: cTxt
    logical         :: bClose

    !--- CRLF = C_CARRIAGE_RETURN // C_NEW_LINE
    CRLF = Achar(13) // Achar(10)
    !--------------------------------------------------------/\

    myscreen = initwindow(320, 240, closeflag=.TRUE.)
    mybutton = createbutton(270, 210, 40, 20, "Close", handle_button)

    !--------------Added-------------------------------------\/
    root_menu = addmenu("", MENU_FOR_WINDOW)
    file_menu = addmenu("File", root_menu)

    item_temp = addmenuitem("Open another window...", file_menu, handle_winopen)
    item_temp = addmenuitem("Close a window...", file_menu, handle_winclose)
    item_temp = addmenuitem("Save Screenshot...", file_menu, savescreen)
    item_temp = addmenuitem("Open", file_menu, handle_open)
    run_item = addmenuitem("Run", file_menu, handle_run)
    item_temp = addmenuitem("Quit", file_menu, quitwndo)


    cTxt =  'This is the second window inialized ' //CRLF// &
            'with the closeflag = .TRUE.  Let''s try and ' //CRLF// &
            'close the second window.' //CRLF
    bClose = .TRUE.
    CALL SplashScreen( 'Second Window', cTxt, 4, bClose )

    cTxt =  'This is the third window inialized but ' //CRLF// &
            'with the closeflag = .FALSE.  Let''s try and ' //CRLF// &
            'select-> FILE/OPEN ANOTHER WINDOW and then ' //CRLF// &
            'select-> FILE/CLOSE A WINDOW.' //CRLF
    bClose = .FALSE.
    CALL SplashScreen( 'Third Window', cTxt, 3, bClose )
    !--------------------------------------------------------/\

    call enableresize(handle_resize)

    task = -1
    itr = 3

    do while(task .NE. task_quit)
        call draw_window()
        call loop()
        select case(task)
            case (task_open)
                call openfile()
            case (task_run)
                call longrun()
    !--------------Added-------------------------------------\/
            case (task_win)
                itr = itr + 1
                call openwin()
            case (task_close)
                call closewin()
    !--------------------------------------------------------/\
        end select
    end do

    call closewindow(myscreen)

    CONTAINS !--- SUBROUTINES

    subroutine draw_window()
    use appgraphics
    implicit none
        integer::w,h

        integer::tw
        character(100)::info

        w = getmaxx()
        h = getmaxy()

        call setbuttonposition(mybutton, w-50, h-30, 40, 20)

        write(info, '(A5,1X,I5,A1,I5)') "Size:", w, "x", h

        call setviewport(0, 0, w, 40, .FALSE.)
        call clearviewport()
        tw = textwidth(trim(info))
        call outtextxy( (w/2-tw/2), 5, trim(info))

    end subroutine draw_window

    subroutine handle_button()
    use appgraphics, only: stopidle
    implicit none

        task = task_quit
        call stopidle()

    end subroutine handle_button

    subroutine handle_resize()
    use appgraphics
    implicit none

        call stopidle()

    end subroutine handle_resize

    subroutine handle_open()
    use appgraphics
    implicit none

        task = task_open
        call stopidle()

    end subroutine handle_open

    !--------------Added-------------------------------------\/
    subroutine handle_winopen()
    use appgraphics
    implicit none

        task = task_win
        call stopidle()

    end subroutine handle_winopen

    subroutine openwin()
        USE appgraphics
        implicit none
        character(4) :: cItr

        write( cItr, '(I3)' ) Itr
        cTxt =  'Open window number '// cItr //CRLF// &
                'with the closeflag = .FALSE.  Let''s try and ' //CRLF// &
                'select-> FILE/CLOSE A WINDOW.' //CRLF
        bClose = .FALSE.
        CALL SplashScreen( 'New Window', cTxt, 3, bClose )

    end subroutine openwin

    subroutine handle_winclose()
    use appgraphics
    implicit none

        task = task_close
        call stopidle()

    end subroutine handle_winclose

    subroutine closewin()
        USE appgraphics
        implicit none
        integer::newscreen

        !--- Close the windows
!        CALL closewindow (ALL_WINDOWS)
!        CALL closewindow (NO_CURRENT_WINDOW)
!        CALL closewindow()

        !--- Get main menu window and set it to the current window
        newscreen = getsignallingwindow ( )

        !--- Close a window
        CALL setcurrentwindow (newscreen)
        CALL closewindow(newscreen)

    end subroutine closewin

    subroutine openfile()
        USE appgraphics, ONLY: dlgopenfile
        implicit none

        CHARACTER(255)  :: input_file_name

        !   Appgraphics function dlgopenfile (filename, maskdesc, mask, title)
        input_file_name= repeat(' ', 255)

        IF( dlgopenfile( &
            input_file_name, 'Data', '*.raw', 'Enter data file') ) THEN

            Print *, "You've selected "//trim(input_file_name)
        ELSE
            Print *, "No file was selected"
        END IF

        input_file_name = TRIM(input_file_name)

    end subroutine openfile

    subroutine savescreen()
        use appgraphics, only: writeimagefile
        implicit none

        ! This call will open a file dialog since we haven't
        ! specified a filename
        call writeimagefile()

    end subroutine savescreen

    subroutine handle_run()
        use appgraphics, only: stopidle
        implicit none

        task = task_run
        call stopidle()

    end subroutine handle_run

    subroutine longrun()
        implicit none

        real::starttime, nowtime

            call enablemenuitem(run_item, .FALSE.)

            call cpu_time(starttime)
            nowtime = starttime
            do while(nowtime - starttime .LT. 0.01)
                call cpu_time(nowtime)
                WRITE( *,'(A1$)') , "."
            end do

            call enablemenuitem(run_item, .TRUE.)

    end subroutine longrun

    subroutine quitwndo()
        use appgraphics, only: stopidle
        implicit none

        task = task_quit
        call stopidle()

    end subroutine quitwndo

    !
    !--------------------------------------------------------
    Subroutine SplashScreen( cMenu, cTxt, nDelaysec, bClose )
    ! Parameters:
    !   cMenu:      text used in the menu title bar
    !   cTxt:       text narrative in the textbox
    !   nDelaysec:  number seconds delayed
        implicit none

        character(*), intent(IN) :: cMenu
        character(*), intent(IN) :: cTxt
        integer, intent(IN)      :: nDelaysec
        logical, intent(IN)      :: bClose

        character(LEN(cTxt))     :: cTxt2
        character(2) :: CRLF
        integer :: textbox, timerscreen, myscreen
        integer :: tw, w, wd, h, ht, nlen

        !--- CRLF = C_CARRIAGE_RETURN // C_NEW_LINE
          CRLF = Achar(13) // Achar(10)

        !--- Line width of text is 64 characters/line
        nlen = LEN( TRIM(cTxt) )  ! lenstr(s)
        cTxt2 = cTxt(1:nlen)

        ht = 100
        wd = 0

        timerscreen = initwindow(400, ht, title=cMenu, &
            left=300, top=200, closeflag=bClose)

        call setcolor(BLACK)
        call setbkcolor(WHITE)
        call clearviewport()

        w = getmaxx()
        h = getmaxy()

        call settextjustify(LEFT_TEXT, TOP_TEXT)
        call settextstyle (SANS_SERIF_FONT, HORIZ_DIR, 16)

        tw = textwidth(TRIM(cTxt2))
        cTxt2 = TRIM(cTxt2)
        call outtextxy( (w/2-tw/2+wd), h/2-h/5, TRIM(cTxt2) )

        call startidle (nDelaysec*1000)
        CALL stopidle( )

        call refreshall( )

        !--- Set the main menu window to the current window
        CALL setcurrentwindow (myscreen)

        IF ( bClose ) THEN
            !--- Then close the second window
            CALL closewindow(timerscreen)
        ELSE
            !--- Don't close the window.
        ENDIF

        RETURN

    End Subroutine SplashScreen
    !--------------------------------------------------------/\
end program resizing

Re: On AppGraphics basics

hello Jeff,
To close a dialog I used Call closegraph(CURRENT_WINDOW)
The following subroutine is called from the last statement     Ignore = createbutton(5,80,50,20,"continue", cont)
in the dlg routine:

   Subroutine cont
    use appgraphics
        Call closegraph(CURRENT_WINDOW)
        call setcurrentwindow (initW)
    end subroutine cont

The compiler came with the  error message: undefined reference to `closegraph_'
What is going wrong?

Re: On AppGraphics basics

Klaus Asmus wrote:

The compiler came with the  error message: undefined reference to `closegraph_'
What is going wrong?

Klaus,

You have to use closewindow.  The function used to be called closegraph, but the documentation was never updated.  I'll get that fixed too.

Jeff Armstrong
Approximatrix, LLC

Re: On AppGraphics basics

drfrank wrote:

The complete listing of your revised resize routine is attached below...

Frank,

I'll see what's happening.  The internal mechanics of AppGraphics are a bit complicated in order to isolate users from the Windows API.  I would expect some issues with this high level of abstraction.

Jeff Armstrong
Approximatrix, LLC

Re: On AppGraphics basics

thanks Jeff,
Call closewindow(CURRENT_WINDOW) is working
Klaus

Re: On AppGraphics basics

Frank,

I looked through your code, and I ran across a few problems.  The biggest thing to remember is that you'll need to maintain a list of window identifiers as you create them so that you can close them yourself.

In your closewin subroutine, you ask for the signalling window and then immediately close it. However, the signalling window in this case would be your main window because the menu option that (eventually) causes the closewin subroutine to execute is present in your main window.  The getsignallingwindow call, which should usually only be called from within a callback, will return the window from which the callback originated.  So a button or a menu item in a given window,, when clicked, will return that window's identifier within its callback when getsignallingwindow is called.

I reworked your code to include a new array, child_windows, that is populated with window identifiers every time you call your SplashScreen subroutine.   When you call closewin, it looks through the list for a valid window identifier and closes it.  The very slightly modified code appears below:

!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
program resizing
use appgraphics
implicit none

    integer::myscreen
    integer::mybutton
    integer, volatile::task

    integer, parameter::task_quit=0
    integer, parameter::task_open=1
    integer, parameter::task_run=2
    integer::run_item

    !--------------Added-------------------------------------\/
    integer, parameter::task_win=3
    integer, parameter::task_close=4
    integer         :: root_menu, file_menu, item_temp, win_menu, itr
    character(2)    :: CRLF
    character(512)  :: cTxt
    logical         :: bClose
    
    integer, dimension(256)::child_windows

    !--- CRLF = C_CARRIAGE_RETURN // C_NEW_LINE
    CRLF = Achar(13) // Achar(10)
    !--------------------------------------------------------/\
    
    child_windows = -1
    
    myscreen = initwindow(320, 240, closeflag=.TRUE.)
    mybutton = createbutton(270, 210, 40, 20, "Close", handle_button)

    !--------------Added-------------------------------------\/
    root_menu = addmenu("", MENU_FOR_WINDOW)
    file_menu = addmenu("File", root_menu)

    item_temp = addmenuitem("Open another window...", file_menu, handle_winopen)
    item_temp = addmenuitem("Close a window...", file_menu, handle_winclose)
    item_temp = addmenuitem("Save Screenshot...", file_menu, savescreen)
    item_temp = addmenuitem("Open", file_menu, handle_open)
    run_item = addmenuitem("Run", file_menu, handle_run)
    item_temp = addmenuitem("Quit", file_menu, quitwndo)


    cTxt =  'This is the second window inialized ' //CRLF// &
            'with the closeflag = .TRUE.  Let''s try and ' //CRLF// &
            'close the second window.' //CRLF
    bClose = .TRUE.
    CALL SplashScreen( 'Second Window', cTxt, 4, bClose )

    cTxt =  'This is the third window inialized but ' //CRLF// &
            'with the closeflag = .FALSE.  Let''s try and ' //CRLF// &
            'select-> FILE/OPEN ANOTHER WINDOW and then ' //CRLF// &
            'select-> FILE/CLOSE A WINDOW.' //CRLF
    bClose = .FALSE.
    CALL SplashScreen( 'Third Window', cTxt, 3, bClose )
    !--------------------------------------------------------/\

    call enableresize(handle_resize)

    task = -1
    itr = 3

    do while(task .NE. task_quit)
        call draw_window()
        task = -1
        call loop()
        select case(task)
            case (task_open)
                call openfile()
            case (task_run)
                call longrun()
    !--------------Added-------------------------------------\/
            case (task_win)
                itr = itr + 1
                call openwin()
            case (task_close)
                call closewin()
    !--------------------------------------------------------/\
        end select

    end do

    call closewindow(myscreen)

    CONTAINS !--- SUBROUTINES

    subroutine draw_window()
    use appgraphics
    implicit none
        integer::w,h

        integer::tw
        character(100)::info
        
        call setcurrentwindow(myscreen)
        
        w = getmaxx()
        h = getmaxy()

        call setbuttonposition(mybutton, w-50, h-30, 40, 20)

        write(info, '(A5,1X,I5,A1,I5)') "Size:", w, "x", h

        call setviewport(0, 0, w, 40, .FALSE.)
        call clearviewport()
        tw = textwidth(trim(info))
        call outtextxy( (w/2-tw/2), 5, trim(info))

    end subroutine draw_window

    subroutine handle_button()
    use appgraphics, only: stopidle
    implicit none

        task = task_quit
        call stopidle()

    end subroutine handle_button

    subroutine handle_resize()
    use appgraphics
    implicit none

        call stopidle()

    end subroutine handle_resize

    subroutine handle_open()
    use appgraphics
    implicit none

        task = task_open
        call stopidle()

    end subroutine handle_open

    !--------------Added-------------------------------------\/
    subroutine handle_winopen()
    use appgraphics
    implicit none

        task = task_win
        call stopidle()

    end subroutine handle_winopen

    subroutine openwin()
        USE appgraphics
        implicit none
        character(4) :: cItr

        write( cItr, '(I3)' ) Itr
        cTxt =  'Open window number '// cItr //CRLF// &
                'with the closeflag = .FALSE.  Let''s try and ' //CRLF// &
                'select-> FILE/CLOSE A WINDOW.' //CRLF
        bClose = .FALSE.
        CALL SplashScreen( 'New Window', cTxt, 3, bClose )

    end subroutine openwin

    subroutine handle_winclose()
    use appgraphics
    implicit none

        task = task_close
        call stopidle()

    end subroutine handle_winclose

    subroutine closewin()
        USE appgraphics
        implicit none
        integer::i

        !--- Close the windows
!        CALL closewindow (ALL_WINDOWS)
!        CALL closewindow (NO_CURRENT_WINDOW)
!        CALL closewindow()

        do i=1,ubound(child_windows, 1)
            if(child_windows(i) .GE. 0) then
                call closewindow(child_windows(i))
                child_windows(i) = -1
                exit
            end if
        end do
        
    end subroutine closewin

    subroutine openfile()
        USE appgraphics, ONLY: dlgopenfile
        implicit none

        CHARACTER(255)  :: input_file_name

        !   Appgraphics function dlgopenfile (filename, maskdesc, mask, title)
        input_file_name= repeat(' ', 255)

        IF( dlgopenfile( &
            input_file_name, 'Data', '*.raw', 'Enter data file') ) THEN

            Print *, "You've selected "//trim(input_file_name)
        ELSE
            Print *, "No file was selected"
        END IF

        input_file_name = TRIM(input_file_name)

    end subroutine openfile

    subroutine savescreen()
        use appgraphics, only: writeimagefile
        implicit none

        ! This call will open a file dialog since we haven't
        ! specified a filename
        call writeimagefile()

    end subroutine savescreen

    subroutine handle_run()
        use appgraphics, only: stopidle
        implicit none

        task = task_run
        call stopidle()

    end subroutine handle_run

    subroutine longrun()
        implicit none

        real::starttime, nowtime

            call enablemenuitem(run_item, .FALSE.)

            call cpu_time(starttime)
            nowtime = starttime
            do while(nowtime - starttime .LT. 0.01)
                call cpu_time(nowtime)
                WRITE( *,'(A1$)') , "."
            end do

            call enablemenuitem(run_item, .TRUE.)

    end subroutine longrun

    subroutine quitwndo()
        use appgraphics, only: stopidle
        implicit none

        task = task_quit
        call stopidle()

    end subroutine quitwndo

    !
    !--------------------------------------------------------
    Subroutine SplashScreen( cMenu, cTxt, nDelaysec, bClose )
    ! Parameters:
    !   cMenu:      text used in the menu title bar
    !   cTxt:       text narrative in the textbox
    !   nDelaysec:  number seconds delayed
        implicit none

        character(*), intent(IN) :: cMenu
        character(*), intent(IN) :: cTxt
        integer, intent(IN)      :: nDelaysec
        logical, intent(IN)      :: bClose

        character(LEN(cTxt))     :: cTxt2
        character(2) :: CRLF
        integer :: textbox, timerscreen, myscreen
        integer :: tw, w, wd, h, ht, nlen
        integer::i

        !--- CRLF = C_CARRIAGE_RETURN // C_NEW_LINE
          CRLF = Achar(13) // Achar(10)

        !--- Line width of text is 64 characters/line
        nlen = LEN( TRIM(cTxt) )  ! lenstr(s)
        cTxt2 = cTxt(1:nlen)

        ht = 100
        wd = 0

        timerscreen = initwindow(400, ht, title=cMenu, &
            left=300, top=200, closeflag=bClose)
            
        do i=1, ubound(child_windows, 1)
            if(child_windows(i) .EQ. -1) then
                child_windows(i) = timerscreen
                exit
            end if
        end do

        call setcolor(BLACK)
        call setbkcolor(WHITE)
        call clearviewport()

        w = getmaxx()
        h = getmaxy()

        call settextjustify(LEFT_TEXT, TOP_TEXT)
        call settextstyle (SANS_SERIF_FONT, HORIZ_DIR, 16)

        tw = textwidth(TRIM(cTxt2))
        cTxt2 = TRIM(cTxt2)
        call outtextxy( (w/2-tw/2+wd), h/2-h/5, TRIM(cTxt2) )

        call startidle (nDelaysec*1000)
        CALL stopidle( )

        call refreshall( )

        !--- Set the main menu window to the current window
        CALL setcurrentwindow (myscreen)

        IF ( bClose ) THEN
            !--- Then close the second window
            CALL closewindow(timerscreen)
        ELSE
            !--- Don't close the window.
        ENDIF

        RETURN

    End Subroutine SplashScreen
    !--------------------------------------------------------/\
end program resizing

I do plan on posting a multiple window tutorial tomorrow.  It might be easier to follow for other users as we can do away with some of the complexities of this example.

Jeff Armstrong
Approximatrix, LLC

Re: On AppGraphics basics

Hi Jeff,

Your fix is clever, concise, and effective.  Just the piece I was missing and didn't realize.

I hope others will find your revised example useful and encourage more application of Appgraphics.

Thanks again Jeff,

--Frank

Re: On AppGraphics basics

Frank,

I wanted to quickly note that there is, in fact, a bug related to multiple windows.  Closing any child window can possibly lead to the error concerning no drawing window available under just about any circumstance due to, oddly enough, mouse handling.  A new version of AppGraphics will have a fix for the bug, and everything should be released tomorrow morning.

Jeff Armstrong
Approximatrix, LLC