Welcome, Guest
You have to register before you can post on our site.

Username/Email:
  

Password
  





Search Forums

(Advanced Search)

Forum Statistics
» Members: 326
» Latest member: hafsahomar
» Forum threads: 1,758
» Forum posts: 17,919

Full Statistics

Latest Threads
MBA Assignment Help in Du...
Forum: General Discussion
Last Post: hafsahomar
06-11-2025, 07:05 AM
» Replies: 0
» Views: 11
лучшие песни медляки слуш...
Forum: Petr
Last Post: WillieTop
06-08-2025, 02:21 AM
» Replies: 0
» Views: 24
пинк слушать онлайн беспл...
Forum: SMcNeill
Last Post: WillieTop
06-08-2025, 02:20 AM
» Replies: 0
» Views: 22
скачать музыку российскую...
Forum: madscijr
Last Post: WillieTop
06-08-2025, 02:18 AM
» Replies: 0
» Views: 23
нежная музыка mp3 скачать
Forum: Keybone
Last Post: WillieTop
06-08-2025, 02:17 AM
» Replies: 0
» Views: 21
лучшая песня слушать онла...
Forum: bplus
Last Post: WillieTop
06-08-2025, 02:16 AM
» Replies: 0
» Views: 24
пикник слушать онлайн луч...
Forum: Spriggsy
Last Post: WillieTop
06-08-2025, 02:15 AM
» Replies: 0
» Views: 22
какая сейчас популярная м...
Forum: RhoSigma
Last Post: WillieTop
06-08-2025, 02:14 AM
» Replies: 0
» Views: 18
хит лета 2019 музыка на т...
Forum: Christmas Code
Last Post: WillieTop
06-08-2025, 02:12 AM
» Replies: 0
» Views: 25
бесплатная музыка mp3 рег...
Forum: Works in Progress
Last Post: WillieTop
06-08-2025, 02:11 AM
» Replies: 0
» Views: 17

 
Lightbulb SaveImage - attempt to make it faster
Posted by: mnrvovrfc - 12-09-2022, 10:26 AM - Forum: Utilities - Replies (5)

This is the "SaveImage" routine from the Wiki, changed by me to try to make it faster, but it seems to be a failure with big pictures. For stuff larger than 1920x1080 might have to set even greater string buffers for "d$" and "r$". It was quite fast on my old Toshiba laptop purchased in December 2006 with 1024x768 resolution.

The "DIM" declarations are to ensure it works in "OPTION _EXPLICIT" mode.

!Needs testing!

Code: (Select All)
''from QB64 wiki
''modifications by mnrvovrfc
''this uses MID$() in replacement up to greatly speed up
''  the reading of the screen,
''  it avoids concatenation of strings as much as possible
''  which is notoriously slow when millions of bytes are involved

Sub SaveImage (image As Long, filename As String)
    Dim ld As Long, lr As Long, lx As Long
    Dim bytesperpixel&, bpp&, lastsource&, px&, py&, cv&, c&, f&, x&, y&, b$, d$, r$, padder$, rrr$, filename2$
    bytesperpixel& = _PixelSize(image&)
    If bytesperpixel& = 0 Then Print "Text modes unsupported!": End
    If bytesperpixel& = 1 Then bpp& = 8 Else bpp& = 24
    x& = _Width(image&)
    y& = _Height(image&)
    b$ = "BM????QB64????" + MKL$(40) + MKL$(x&) + MKL$(y&) + MKI$(1) + MKI$(bpp&) + MKL$(0) + "????" + String$(16, 0) 'partial BMP header info(???? to be filled later)
    If bytesperpixel& = 1 Then
        For c& = 0 To 255 ' read BGR color settings from JPG image + 1 byte spacer(CHR$(0))
            cv& = _PaletteColor(c&, image&) ' color attribute to read.
            b$ = b$ + Chr$(_Blue32(cv&)) + Chr$(_Green32(cv&)) + Chr$(_Red32(cv&)) + Chr$(0) 'spacer byte
        Next
    End If
    Mid$(b$, 11, 4) = MKL$(Len(b$)) ' image pixel data offset(BMP header)
    d$ = Space$(50000000)
    ld = 1
    lastsource& = _Source
    _Source image&
    If ((x& * 3) Mod 4) Then padder$ = String$(4 - ((x& * 3) Mod 4), 0)
    For py& = y& - 1 To 0 Step -1 ' read JPG image pixel color data
        r$ = Space$(10000000)
        lr = 1
        For px& = 0 To x& - 1
            c& = Point(px&, py&) 'POINT 32 bit values are large LONG values
            If bytesperpixel& = 1 Then
                rrr$ = Chr$(c&)
            Else
                rrr$ = Left$(MKL$(c&), 3)
            End If
            lx = Len(rrr$)
            Mid$(r$, lr, lx) = rrr$
            lr = lr + lx
        Next px&
        r$ = Left$(r$, lr - 1)
        rrr$ = r$ + padder$
        lx = Len(rrr$)
        Mid$(d$, ld, lx) = rrr$
        ld = ld + lx
    Next py&
    _Source lastsource&
    d$ = Left$(d$, ld - 1)
    Mid$(b$, 35, 4) = MKL$(Len(d$)) ' image size(BMP header)
    Mid$(b$, 3, 4) = MKL$(Len(b$) + Len(d$)) ' size of data file(BMP header)
    filename2$ = filename$
    If LCase$(Right$(filename$, 4)) <> ".bmp" Then filename2$ = filename$ + ".bmp"
    f& = FreeFile
    Open filename2$ For Output As #f&: Close #f& ' erases an existing file
    Open filename2$ For Binary As #f&
    Put #f&, , b$
    Put #f&, , d$
    Close #f&
End Sub

Print this item

  DAY 028: _SCREENPRINT
Posted by: Pete - 12-09-2022, 03:40 AM - Forum: Keyword of the Day! - No Replies

I ain't got nothin' but KEYWORDS, eight days a week...

So let's talk _SCREENPRINT, the little bro to the bigger and better Win32 SENDKEYS function.

SYNTAX: _SCREENPRINT text$

Note: This keyword is not supported in Linux and Mac Operating Systems.

So what does it do?

_SCREENPRINT is acts as a virtual keypress and text transmitter. It is limited in the key combos available, which can be seen in the table, below...

Code: (Select All)
CTRL + A = CHR$(1)   ☺  StartHeader (SOH)    CTRL + B = CHR$(2)   ☻  StartText         (STX)
CTRL + C = CHR$(3)   ♥  EndText     (ETX)    CTRL + D = CHR$(4)   ♦  EndOfTransmit     (EOT)
CTRL + E = CHR$(5)   ♣  Enquiry     (ENQ)    CTRL + F = CHR$(6)   ♠  Acknowledge       (ACK)
CTRL + G = CHR$(7)   •  BEEP        (BEL)    CTRL + H = CHR$(8)   ◘  [Backspace]       (BS)
CTRL + I = CHR$(9)   ○  Horiz.Tab   [Tab]    CTRL + J = CHR$(10)  ◙  LineFeed(printer) (LF)
CTRL + K = CHR$(11)  ♂  Vert. Tab   (VT)     CTRL + L = CHR$(12)  ♀  FormFeed(printer) (FF)
CTRL + M = CHR$(13)  ♪  [Enter]     (CR)     CTRL + N = CHR$(14)  ♫  ShiftOut          (SO)
CTRL + O = CHR$(15)  ☼  ShiftIn     (SI)     CTRL + P = CHR$(16)  ►  DataLinkEscape    (DLE)
CTRL + Q = CHR$(17)  ◄  DevControl1 (DC1)    CTRL + R = CHR$(18)  ↕  DeviceControl2    (DC2)
CTRL + S = CHR$(19)  ‼  DevControl3 (DC3)    CTRL + T = CHR$(20)  ¶  DeviceControl4    (DC4)
CTRL + U = CHR$(21)  §  NegativeACK (NAK)    CTRL + V = CHR$(22)  ▬  Synchronous Idle  (SYN)
CTRL + W = CHR$(23)  ↨  EndTXBlock  (ETB)    CTRL + X = CHR$(24)  ↑  Cancel            (CAN)
CTRL + Y = CHR$(25)  ↓  EndMedium   (EM)     CTRL + Z = CHR$(26)  →  End Of File(SUB)  (EOF)

So let's take a look at the first entry, Ctrl+A. This is the key combo we use to highlight text in other apps. 

_SCREENPRINT CHR$(1) will therefore highlight all the text on another open and active app.

Wait for it to compile and start. When you see the window open, click back on this browser window...
Code: (Select All)
_DELAY 5 ' Give yourself some time to click another app, like this browser.
_SCREENPRINT CHR$(1)

Cool, right? Well now _SCREENPRINT also works progressively, so if we wanted to copy that text to our clipboard, we would just code...

Code: (Select All)
_DELAY 5 ' Give yourself some time to click another app, like this browser.
_SCREENPRINT CHR$(1)
_SCREENPRINT CHR$(3) ' See the chart. This is Ctrl+C, COPY.
' Now let's see if it worked by reading the clipboard...
PRINT _CLIPBOARD$

If you wanted to paste, it's _SCREENPRINT CHR$(22), btw.

So speaking of pasting, lets try a select all, copy/paste from the QB64 IDE into Notepad...

Windows only example.
Code: (Select All)
_CLIPBOARD$ = ""
_DELAY 1
_SCREENHIDE
DO
    _LIMIT 5
LOOP UNTIL LEN(_CLIPBOARD$)
SHELL _HIDE "start Notepad.exe" ' Open Windows Notepad.
_DELAY 1
_SCREENPRINT _CLIPBOARD$
_DELAY 3
_SCREENSHOW
PRINT: PRINT " Cool, right?"

So with _SCREENPRINT we can do things like fill out web forms (Note: _SCREENPRINT CHR$(9) is Tab to change form fields), gather text from other apps, execute commands with _SCREENPRINT CHR$(13) the Enter key, etc.

For some routines like ALT + F to open the QB64 IDE File Menu, you need something more robust like Win32 API SENDKEYS.

Windows only Win32 API SENDKEYS example.
Code: (Select All)
CONST VK_ALT = &H12 'Alt key
CONST KEYEVENTF_KEYUP = &H2 ' Release key.

DECLARE DYNAMIC LIBRARY "user32"
    SUB SENDKEYS ALIAS keybd_event (BYVAL bVk AS LONG, BYVAL bScan AS LONG, BYVAL dwFlags AS LONG, BYVAL dwExtraInfo AS LONG)
END DECLARE

PRINT "Click the QB64 IDE window after I hide!"
_DELAY 5
_SCREENHIDE ' Get the app window the hell out of our way...
_DELAY 5

SENDKEYS VK_ALT, 0, 0, 0 ' Alt
SENDKEYS &H46, 0, 0, 0 ' F open IDE file menu.
_DELAY .1
SENDKEYS &H45, 0, KEYEVENTF_KEYUP, 0 ' Release F key.
SENDKEYS VK_ALT, 0, KEYEVENTF_KEYUP, 0 ' ' Release Alt key.
_DELAY 5
_SCREENSHOW

Pete

Print this item

  Chat App / Messenger
Posted by: Pete - 12-09-2022, 02:19 AM - Forum: Programs - Replies (10)

This is a TCP/IP routine. Windows users will need to Okay it, on the first run, with Windows Defender.

I posted two versions. The first minimizes and restores the chat window to activate it. The second uses QB64 _SCREENCLICK. auto-activation allows us to continuously send messages back and forth without clicking the window each rotation.

Sorry Linux and mac users, I tried, but to return focus to each active chat window requires one Win32 API command to restore the window, and mn pointed out that _SCREENCLICK isn't supported in these operating systems. If anyone can figure out a QB64 way to force a minimized window back to the desktop, please let me know.

So to gives this a try, you need to copy and run both the "host" and client" programs. Since the host starts the client, you will need to name the client as messenger_client.bas and save it as messenger_client.exe before you run the host program.

Min/Restore Version

Host

Code: (Select All)
DECLARE DYNAMIC LIBRARY "user32"
    FUNCTION ShowWindow& (BYVAL hWnd AS LONG, BYVAL nCmdShow AS LONG) 'maximize process
END DECLARE

_SCREENMOVE 0, 0
title$ = "Messenger_Host"
_TITLE (title$)
_DELAY .1
hWnd& = _WINDOWHANDLE

_SCREENMOVE 0, 0 ' Set up this host window to the left of your desktop.
WIDTH 60, 25
PALETTE 0, 8
COLOR 7, 0
CLS
IF NOT _FILEEXISTS("messenger_client.exe") THEN PRINT "Cannot find file: messenger_client.exe. Ending...": END
DIM host_msg AS STRING, client_msg AS STRING
DO
    IF initiate = 0 THEN ' This only needs to be performed once, to open the client window.
        DO UNTIL x ' Stay in loop until window determines if it is the host or client window.
            x = _OPENCLIENT("TCP/IP:1234:localhost") ' Used to establish a TCP/IP routine.
            IF x = 0 THEN
                x = _OPENHOST("TCP/IP:1234") ' Note the host and clinet must have the same 1234 I.D. number.
                a$ = "Opening as host." ' x channel is now open and this window becomes the host.
            ELSE
                a$ = "Opening as client." ' Should not go here for this demo.
            END IF
            PRINT a$
        LOOP
        SHELL _HIDE _DONTWAIT "START messenger_client.exe" ' Open the client window.
        initiate = -1 ' Switches this block statement off for all subsequent loops.
    END IF

    IF z = 0 THEN ' Initiates an open channel number when zero.
        DO
            z = _OPENCONNECTION(x) ' Checks if host is available to transfer data.
        LOOP UNTIL z
        PRINT "Connection established."
        _DELAY 1
        LOCATE 2: PRINT SPACE$(_WIDTH * 2) ' Remove previous text.
        LOCATE 3, 1
        GOSUB focus
    END IF

    ' Okay, time to input something on the host that will be communicated to the client.
    COLOR 7: LINE INPUT "Message to client: "; host_msg: PRINT

    PUT #z, , host_msg ' Input is now entered into TCP/IP routine.
    IF host_msg = "" THEN SYSTEM

    DO
        GET #z, , client_msg
    LOOP UNTIL LEN(client_msg) ' Exits loop when a return msg is received.

    COLOR 6: PRINT "Message from client: "; client_msg: PRINT

    host_msg = "": PUT #z, , host_msg$ ' Now put our client value back into the routine. Failure to do so would result in the client not waiting in the GET #x DO/LOOP.
    _KEYCLEAR ' Prevents typing before ready.

    GOSUB focus
LOOP

focus:
_SCREENICON
y& = ShowWindow&(hWnd&, 9)
RETURN


Client (Remember, name and save this one as messenger_client.exe).
Code: (Select All)
DECLARE DYNAMIC LIBRARY "user32"
    FUNCTION ShowWindow& (BYVAL hWnd AS LONG, BYVAL nCmdShow AS LONG) 'maximize process
END DECLARE

title$ = "Messenger_Client"
_TITLE (title$)
_DELAY .1

hWnd& = _WINDOWHANDLE

DIM host_msg AS STRING, client_msg AS STRING
_SCREENMOVE 600, 0 ' Set up this client window next to your host window.
WIDTH 50, 25
PALETTE 0, 8
COLOR 7, 0
CLS
x = _OPENCLIENT("TCP/IP:1234:localhost") ' Used to establish a TCP/IP routine.
PRINT "Opened as client.": PRINT
DO UNTIL x = 0 ' Prevents running if this app is opened without using host.
    DO
        _LIMIT 30
        GET #x, , host_msg ' Waits until it receives message sent from the host.
    LOOP UNTIL LEN(host_msg)

    COLOR 6: PRINT "Message from host: "; host_msg
    PRINT
    _KEYCLEAR ' Prevents typing before ready.

    GOSUB focus

    COLOR 7: LINE INPUT "Message to host: "; client_msg: PRINT
    IF client_msg = "" THEN SYSTEM

    PUT #x, , client_msg
LOOP
END

focus:
_SCREENICON
y& = ShowWindow&(hWnd&, 9)
RETURN

This project is slightly modified from my October 28th post at The QBasic Forum: https://www.tapatalk.com/groups/qbasic/t...39735.html

That one used all Win32 API to find, minimize and restore the window. If you are interested in seeing the extra API stuff, check it out. Also, I play loose and fast with the API type variables. So far I've only been stung once by changing an _OFFSET to a LONG. Most of the time you can get away from convention.

Oh, why bother minimizing and restoring? Well, so far none of us can figure out a way to get a window not just in focus, but active and in focus after another window is made active. Spriggsy and I both came up with the min/restore trick at the same time, which was pretty funny.

Okay, for Linus and Mac fans... (And yes, I made _SCREENCLICK 'smart' so you can move the windows around).

_SCREENCLICK Version: Same App, but uses _SCREENCLICK instead of Win32 API to activate each window.

Host
Code: (Select All)
_SCREENMOVE 0, 0
title$ = "Messenger_Host"
_TITLE (title$)
_DELAY .1

_SCREENMOVE 0, 0 ' Set up this host window to the left of your desktop.
WIDTH 60, 25
PALETTE 0, 8
COLOR 7, 0
CLS
IF NOT _FILEEXISTS("messenger_client.exe") THEN PRINT "Cannot find file: messenger_client.exe. Ending...": END
DIM host_msg AS STRING, client_msg AS STRING
DO
    IF initiate = 0 THEN ' This only needs to be performed once, to open the client window.
        DO UNTIL x ' Stay in loop until window determines if it is the host or client window.
            x = _OPENCLIENT("TCP/IP:1234:localhost") ' Used to establish a TCP/IP routine.
            IF x = 0 THEN
                x = _OPENHOST("TCP/IP:1234") ' Note the host and clinet must have the same 1234 I.D. number.
                a$ = "Opening as host." ' x channel is now open and this window becomes the host.
            ELSE
                a$ = "Opening as client." ' Should not go here for this demo.
            END IF
            PRINT a$
        LOOP
        SHELL _HIDE _DONTWAIT "START messenger_client.exe" ' Open the client window.
        initiate = -1 ' Switches this block statement off for all subsequent loops.
    END IF

    IF z = 0 THEN ' Initiates an open channel number when zero.
        DO
            z = _OPENCONNECTION(x) ' Checks if host is available to transfer data.
        LOOP UNTIL z
        PRINT "Connection established."
        _DELAY 1
        LOCATE 2: PRINT SPACE$(_WIDTH * 2) ' Remove previous text.
        LOCATE 3, 1
        GOSUB focus
    END IF

    ' Okay, time to input something on the host that will be communicated to the client.
    COLOR 7: LINE INPUT "Message to client: "; host_msg: PRINT

    PUT #z, , host_msg ' Input is now entered into TCP/IP routine.
    IF host_msg = "" THEN SYSTEM

    DO
        GET #z, , client_msg
    LOOP UNTIL LEN(client_msg) ' Exits loop when a return msg is received.

    COLOR 6: PRINT "Message from client: "; client_msg: PRINT

    host_msg = "": PUT #z, , host_msg$ ' Now put our client value back into the routine. Failure to do so would result in the client not waiting in the GET #x DO/LOOP.
    _KEYCLEAR ' Prevents typing before ready.

    GOSUB focus
LOOP

focus:
_SCREENCLICK _SCREENX + 60, _SCREENY + 10
RETURN


Client (Name as messenger_client.exe).
Code: (Select All)
title$ = "Messenger_Client"
_TITLE (title$)
_DELAY .1

DIM host_msg AS STRING, client_msg AS STRING
_SCREENMOVE 600, 0 ' Set up this client window next to your host window.
WIDTH 50, 25
PALETTE 0, 8
COLOR 7, 0
CLS
x = _OPENCLIENT("TCP/IP:1234:localhost") ' Used to establish a TCP/IP routine.
PRINT "Opened as client.": PRINT
DO UNTIL x = 0 ' Prevents running if this app is opened without using host.
    DO
        _LIMIT 30
        GET #x, , host_msg ' Waits until it receives message sent from the host.
    LOOP UNTIL LEN(host_msg)

    COLOR 6: PRINT "Message from host: "; host_msg
    PRINT
    _KEYCLEAR ' Prevents typing before ready.

    GOSUB focus

    COLOR 7: LINE INPUT "Message to host: "; client_msg: PRINT
    IF client_msg = "" THEN SYSTEM

    PUT #x, , client_msg
LOOP
END

focus:
_SCREENCLICK _SCREENX + 60, _SCREENY + 10
RETURN


Pete

Print this item

Bug Possible bug with _SCREENICON
Posted by: Pete - 12-08-2022, 09:16 PM - Forum: General Discussion - Replies (7)

Code: (Select All)
_DELAY 2
_SCREENHIDE
_DELAY 5
' Error 5 after delay at line below...
IF _SCREENICON THEN BEEP ' Should beep with value -1 when minimized by _SCREENHIDE.
_SCREENSHOW

So I have done Win32 API min/restore with focus, but now I was looking for an all QB64 method. Since _SCREENHIDE is supposed minimize the program, it seems odd _SCREENICON should throw an error. It should return -1 when the window is minimized. If you REM out the SCREENHIDE and manually minimize, it works just fine, but apparently not when _SCREENHIDE minimizes the window for you.

QB64PE V 3.30 on Win 10 64-bit OS.


Pete

Print this item

  Kanye REST
Posted by: SpriggsySpriggs - 12-08-2022, 07:50 PM - Forum: General Discussion - Replies (8)

Below is some code to grab a random Kanye "Ye" West quote:

Code: (Select All)
Option Explicit
$NoPrefix
$Console:Only
$Unstable:Http

Dim As Long connection: connection = OpenClient("HTTP:https://api.kanye.rest/")
If connection <> 0 And StatusCode(connection) = 200 Then
    Dim As String buf, outbuf
    While Not EOF(connection)
        Get connection, , buf
        outbuf = outbuf + buf
    Wend
    outbuf = Mid$(outbuf, 11)
    outbuf = Mid$(outbuf, 1, Len(outbuf) - 2)
    Print outbuf
    Print: Print "-Kanye West"
End If

Print this item

  Steve's Christmas Assortment
Posted by: SMcNeill - 12-08-2022, 12:16 PM - Forum: Christmas Code - Replies (16)

For folks who want to see how much QB64 has evolved and grown over the last year, I present my little Christmas Program that I was working on and stalled out on last year.


.7z   Xmas v0.5.7z (Size: 173.32 MB / Downloads: 181)

Download from the attachment above.

(IF the forum download is too slow, which seems to be a problem for some of our Linux folks, you can also try to get it directly from my OneDrive: https://1drv.ms/u/s!AknUrv8RXVYMm_Uh2wya...A?e=XIKRX8 It may work better for you.  Wink )



Last year, I ran into an issue that I simply couldn't work around at all -- it was taking FOREVER and EVER to load my list of holiday music into QB64.  No matter how sneakily I tried to sort out a workaround to get past the issue, it still introduced unacceptable levels of lag into the program and made user responses delay by several seconds.  Either that, or else I just introduced a nice 10 minute pause at program startup, so that all the sounds could be loaded at first, before actually playing around with the program.

NEITHER of which were actual workable solutions for the program!!

So... come along this year, QB64-PE gets a complete overhaul of the audio system.  What took 10 minutes to load, we now load in perhaps 3 seconds!  I can once again resume work on my Christmas Project one more time!! 



If anyone wants to see the difference in performance for themselves, just download the file above and extract it.  It's in its own little XMas folder, so it's easy to clean up and remove the clutter from your drive after extracting, if anyone's worried about something like that. Wink

Compile and run... At the very start, you'll see a series of numbers that pop up and count down the screen -- that's the program loading our music files for us, for the first time.  Regardless of if it's incredibly slow or fast for you, once it's finished (or you terminate the process), go into the QB64-PE IDE and navigate to "Options >> Compiler Options" and then toggle the option at the bottom of the list:  "use old audio backend".

Compile and run a second time.

The difference here should be as plain as night and day.  THAT'S how much QB64-PE has changed under the hood in the last year!!

And if that doesn't put you in a Merry Christmas spirit, then BAH HUMBUG TO YOU, MISTER PETE!  Errr...  MISTER SCROOGE!!

Print this item

  DAY 027: _TRIM$
Posted by: Pete - 12-08-2022, 08:56 AM - Forum: Keyword of the Day! - Replies (9)

Space, the final frontier, and when you're sick of space on both sides of your string, use _TRIM$.

_TRIM$ simply removes any leading and/or trailing spaces from any string.

SYNTAX: _TRIM$(mytext$) and can also be used as: _TRIM$("   my text   ")

_TRIM$ is the QB64 answer to, "What do you get when you put LTRIM$ + RTRIM$ together?" Well, until _TRIM$ came along it was LTRIM$(RTRM$(mystring$)). Note: LTRIM$ removes leading spaces, spaces to the "left" and RTRIM$ removes trailing space, spaces to the right, and _TRIM$ removes both.


If there are no spaces, _TRIM$ simply does nothing.

_TRIM$ can be combined with STR$(), which converts a number to a string and removes the trailing space. So why do we need _TRIM? The answer is to get rid of the leading space the system uses to reserve space for a possible negative sign in front of a number even after STR$() is used to convert it to a string.

So while PRINT STR$(-1) is "-1", PRINT STR$(1) would be " 1". To get rid of that leading space we can code either: PRINT LTRIM$(STR$(1)) or PRINT _TRIM$(STR$(1)). Of course most of the time a number will be represented by a variable, so we usually code: MyNumber = 1: MyNumber$ = _TRIM$(STR$(a)).

Code: (Select All)
a = -1
PRINT "|"; a; "|" ' Has one trailing space.
PRINT "|"; STR$(a); "|" ' Chops the trailing space when converting to a string.
PRINT "|"; _TRIM$(STR$(a)); "|" ' Actually not needed here because of the negative number value.
PRINT
a = 1
PRINT "|"; a; "|" ' Has one leading space and one trailing space.
PRINT "|"; STR$(a); "|" ' Chops the trailing space when converting to a string.
PRINT "|"; _TRIM$(STR$(a)); "|" ' Chops the remaining leading space.

Another use is when a DIM statement if made to produce a "fixed" string. A fixed string defines the string length and creates trailing spaces if the string is smaller the dim size created.

Example:

Steve's Spreadsheet
Code: (Select All)
DIM a as STRING * 10 ' All strings named a will be 10 bytes long.
FOR i = 1 TO 3 ' (Not 2 B confused with 1, 2, 3.)  :D
READ a
PRINT "|";a;"|", LEN(a)
PRINT "|";_TRIM$(a);"|", LEN(_TRIM$(a)) ' Here we combine _TRIM$ with LEN() to output the length of our trimmed string.
NEXT

' Steve's sheet spreaders...
DATA Horse,Pig,Mule

_TRIM$ is often used in parsing routines to compare strings as apples to apples, instead of apples to apples with leading and trailing spaces.

So how about some more use examples? Feel free to post yours...

Print this item

  The Dungeon
Posted by: eoredson - 12-08-2022, 05:05 AM - Forum: Utilities - Replies (2)

The link to The Dungeon still remains at:

https://bit.ly/EriksDungeon

For Dngeon12.zip the following is:

   Note: Tasm 4.1 can be found on vetusware

   The Dungeon contains assembly to trap ctrl-break and can be removed from the source by deleting Call Setint/Call Restint.

   This program and source are completely 16-bit and won't load in QB64 because it contains arrays in UDTs..

For Dungeon_v12_QB64.zip it contains no assembly.

Attached is:

   Dngeon12.zip for VB10.

   Dungeon_v12_QB64.zip for QB64.

The readme.txt is:



Code: (Select All)
Program:

  Welcome to The Dungeon Adventure Game v12.0 r3.0. These files, documents,
  and  programs are public domain.  Anyone  may use, rewrite, or distribute
  them  without any fee, charge for use, or packaging requirements.

Files:

  Separate the .zip file with the PKWare utility into the directory:

    c:
    cd \
    md dngeon12
    cd \dngeon12
    copy \temp\dngeon12.zip \dngeon12

  with the command

    pkunzip dngeon12.zip

  The .zip file contains the files:

    ansi.bas    --  opening screen source
    ansi.exe    --  opening screen program
    compile.bat  --  compiling batch program
    compile.txt  --  compile instructions
    desc.sdi    --  program description
    dungeon.bas  --  main dungeon source
    dungeon.doc  --  short documentation
    dungeon.exe  --  main dungeon program
    edit.bas    --  edit utility source
    edit.exe    --  edit utility program
    file_id.diz  --  program description
    features.txt --  list of features
    go.bat      --  startup batch file
    help.bas    --  help menu source
    help.exe    --  help menu program
    keytrap.asm  --  assembly utility source
    list.bat    --  lists source to printer
    mapedit.bas  --  map edit utility source
    mapedit.exe  --  map edit utility program
    page.com    --  display utility
    print.bat    --  prints documentation
    program.txt  --  description of program
    readme.bat  --  displays readme file
    readme.txt  --  readme text file
    swapbas.asm  --  assembly utility source
    util.bas    --  display utility
    util.exe    --  display utility source

Dungeon creates the files:

    datafile.00x --  player data file
    players.dat  --  player data file
    ranklist.dat --  ranking list bulletin

Requirements:

  The  Dungeon is designed  to operate  on any  standard PC, XT, or AT with
  minimum of  256K memory,  a floppy or fixed disk,  and any color graphics
  adapter.




    The DUNGEON v12.0 r3.0 Documentation                          Page  i



Starting the game:

  Enter one of the following commands at the DOS prompt:

    go    -- read documentation and start the program
    print  -- print the documentation
    readme -- display the readme text file

Instructions:

  Playing  is done by  entry on the numeric keypad.  Keys 0, 1, .., 9,  and
  other  symbols  like -, +, and = are used for commands.  Be sure you have
  turned  on numlock before game play.  The Dungeon  also recognizes cursor
  keys for moving in the game without numlock.

Program compiling:

  This disk contains the compile batch files, BASIC source,  and additional
  utility for  the dungeon v12.0.  These files, documents, and programs are
  public domain.  Anyone may use, rewrite,  or distribute them  without any
  fee, charge for use, or packaging requirements.

Compiling requirements:

  The compile program  is designed to operate on any standard PC, XT, or AT
  with 512K, fixed disk, and any monitor.

Starting the compiler:

  Enter one of the following commands at the DOS prompt:

    compile  -- start the compiling process
    list    -- print the source

Compiling instructions:

  Compiling  is done by entering  the subprogram name to  create  with  the
  compile.bat  program.  You should have  the required compiler and library
  listed in the compile.txt file. Example to start: compile dungeon.  Also,
  the  dungeon comes with a makefile  containing instructions for nmake.exe
  to compile the dungeon programs by date of .exe files.

Maintenance release v12.0 r2.0 Fixed/added:

  Alt-Tab to add the globe of power to player inventory.
  Clearing monster array between changing dungeon levels.
  Dungeon level replenish to avoid placing items in rooms.
  Overflow error in info screen for levels greater than 50.
  More than eight monsters attacking player at once.
  Distance to monsters for evade/approach fixed.
  Count loops inside searching for empty dungeon cell.
  Timer beyond midnight pause loop corrected.
  Bulletin report utility display cleaned.
  Added F11/F12 display/clear dungeon symbols.
  Fixed page length in util display.
  Eat keystrokes in second timer pause routine.
  Remove monsters beyond player from attack array.
  Update some counting variables during player movement.
  Trapped interrupt service error during program shells.
  Error with trapped control-break being returned as two-byte null.
  Problem restoring current directory during shells.

    The DUNGEON v12.0 r3.0 Documentation                          Page  ii
[Image: screen1.jpg]



post pictures



Attached Files
.zip   DNGEON12.ZIP (Size: 305.37 KB / Downloads: 47)
.zip   DUNGEON_v12_QB64.zip (Size: 354.78 KB / Downloads: 47)
.zip   dngscrns.zip (Size: 969.18 KB / Downloads: 43)
Print this item

  I just made the 10,000th post!
Posted by: Pete - 12-07-2022, 08:34 PM - Forum: General Discussion - Replies (3)

Wooohooo!

Print this item

  Day 026: ERASE
Posted by: Pete - 12-07-2022, 07:24 AM - Forum: Keyword of the Day! - Replies (12)

ERASE probably should be renamed ARRase, because all it erases is the values stored in a specified array.

ERRASE makes the strings assigned to an array null or makes the numeric values assigned to a numeric array zero.

ERASE ArrayName [, others...]

Example:

Code: (Select All)
DIM Pete(10) AS STRING, var(100) AS INTEGER, cnt(20) AS LONG
ERASE Pete, var, cnt

ERASE can be used with STATIC or DYNAMIC arrays, but there is an important difference. Try running the two following code snippets. 

Code: (Select All)
DIM Pete(1 TO 20) AS INTEGER ' DIM makes Pete a STATIC array.
FOR i = 1 TO 20
    Pete(i) = -i
NEXT

FOR i = 1 TO UBOUND(Pete)
    PRINT Pete(i)
NEXT
SLEEP

ERASE Pete

' All zeros will now be output.
CLS
FOR i = 1 TO 20
    PRINT Pete(i)
NEXT
PRINT " ubound(Pete) is still ="; UBOUND(Pete)
Pete(15) = 101
PRINT: PRINT " Pete(15) ="; Pete(15)

Note: This routine will error out unless we Re-initialize the Pete array.
Code: (Select All)
REDIM Pete(1 TO 20) AS INTEGER ' REDIM makes Pete a DYNAMIC array.
FOR i = 1 TO 20
    Pete(i) = -i
NEXT

FOR i = 1 TO UBOUND(Pete)
    PRINT Pete(i)
NEXT
SLEEP

ERASE Pete

' This will error out unless we do a REDIM Pete(1 TO 20) here.
CLS
FOR i = 1 TO 20
    PRINT Pete(i)
NEXT
PRINT " ubound(Pete) is still ="; UBOUND(Pete)
Pete(15) = 101
PRINT: PRINT " Pete(15) ="; Pete(15)

So ERASE appears to have more value and versatility when used with STATIC arrays, if you consider not de-initialing your array as a benefit.

And what makes an array either static or dynamic? Well...

DIM makes the array static.

REDIM makes the array dynamic

And this important note...

REM $DYNAMIC makes ALL arrays dynamic. So even...

Code: (Select All)
REM $DYNAMIC
DIM Pete(1 to 20)
ERASE Pete
REDIM Pete(1 to 20)

...makes the otherwise static DIM array, of Pete, dynamic. So if you use REM $DYNAMIC at the top of your code, use REDIM because a DIM statement after an ERASE statement won't work with REM DYNAMIC in your code.

REM $STATIC makes ALL arrays static. but...

Code: (Select All)
REM $STATIC
REDIM Pete(1 to 20) ' Change to DIM to get this to work.
ERASE Pete
PRINT Pete(15) ' Errors out because even though we used REM $STATIC REDIM messed it up.

So we've kicked the tires quite a bit here. Anyone want to add anything more?

Pete

Print this item