I'm trying to "show password" on a StringGadget (#PB_String_Password) and my PB noob attempts at it make the thing crash 99% of the times

Code: Select all
EnableExplicit
#Window = 0
Enumeration
#StrG1
#StrG1Pass
#ChHPass
EndEnumeration
Define Hide = 0
If OpenWindow(#Window, 0, 0, 600, 111, "Enter the password", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
StringGadget(#StrG1, 7, 7, 551, 30 , "")
StringGadget(#StrG1Pass, 7, 7, 551, 30 , "", #PB_String_Password)
CheckBoxGadget(#ChHPass, 7, 44, 130, 22, "Hide Password")
If Hide
SetGadgetState(#ChHPass, #True)
HideGadget(#StrG1, #True)
Else
HideGadget(#StrG1Pass, #True)
EndIf
Repeat
Select WaitWindowEvent()
Case #PB_Event_Gadget
Select EventGadget()
Case #ChHPass
If GetGadgetState(#ChHPass) & #PB_Checkbox_Checked
HideGadget(#StrG1, #True)
HideGadget(#StrG1Pass, #False)
Hide = 1
SetGadgetText(#StrG1Pass, GetGadgetText(#StrG1))
SetGadgetText(#StrG1, "") ; we clear it so that we don't have access to the text.
Else
HideGadget(#StrG1Pass, #True)
HideGadget(#StrG1, #False)
Hide = 0
SetGadgetText(#StrG1, GetGadgetText(#StrG1Pass))
EndIf
EndSelect
Case #PB_Event_CloseWindow
CloseWindow(#Window)
Break
EndSelect
ForEver
EndIf
Code: Select all
EnableExplicit
#Window = 0
Enumeration
#StrG1
#StrG1Pass
#ChHPass
EndEnumeration
Define Show = 0
If OpenWindow(#Window, 0, 0, 600, 111, "Enter the password", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
StringGadget(#StrG1, 7, 7, 551, 30 , "")
StringGadget(#StrG1Pass, 7, 7, 551, 30 , "", #PB_String_Password)
CheckBoxGadget(#ChHPass, 7, 44, 130, 22, "Show password")
If Show
SetGadgetState(#ChHPass, #True)
HideGadget(#StrG1Pass, #True)
Else
HideGadget(#StrG1, #True)
EndIf
Repeat
Select WaitWindowEvent()
Case #PB_Event_Gadget
Select EventGadget()
Case #ChHPass
If GetGadgetState(#ChHPass) & #PB_Checkbox_Checked
HideGadget(#StrG1Pass, #True)
HideGadget(#StrG1, #False)
Show = 1
SetGadgetText(#StrG1, GetGadgetText(#StrG1Pass))
Else
SetGadgetText(#StrG1Pass, GetGadgetText(#StrG1))
HideGadget(#StrG1, #True)
HideGadget(#StrG1Pass, #False)
Show = 0
SetGadgetText(#StrG1, "") ; we clear it so that we don't have access to the text.
EndIf
EndSelect
Case #PB_Event_CloseWindow
CloseWindow(#Window)
Break
EndSelect
ForEver
EndIf
Despite the fact that they are well-made, I still believe that these programs are for beginners. The maximum is if you want to quickly make an example for demonstration or if you are starting to develop a GUI. In other cases, creating a GUI takes 0.1% of the program's functionality away from you. That is, you have to write complex functions for one button, which takes several days. You will create a button for this function in 10 seconds.
The PB form editor is really painful on Mac... hoping for the incoming next PB version…
This guy, this guy gets it.
You may also try this multi-platform example to toggle the visibility of a password while using only one single StringGadget (code example at the end of the linked posting).Piero wrote: Mon Feb 03, 2025 7:58 pm Is there a (multiplatform) way to "toggle the flags of a gadget"?
Thanks!
Code: Select all
EnableExplicit
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
Define SecuredPasswordCell.I
Define VisiblePasswordCell.I
CompilerEndIf
Procedure TogglePasswordVisibility(StringGadgetID.I)
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Linux
CompilerIf Subsystem("qt")
If Val(QtScript("gadget(" + Str(StringGadgetID) + ").echoMode")) = 2
QtScript("gadget(" + Str(StringGadgetID) + ").echoMode = 0")
ElseIf Val(QtScript("gadget(" + Str(StringGadgetID) + ").echoMode")) = 0
QtScript("gadget(" + Str(StringGadgetID) + ").echoMode = 2")
EndIf
CompilerElse
gtk_entry_set_visibility_(GadgetID(StringGadgetID),
gtk_entry_get_visibility_(GadgetID(StringGadgetID)) ! 1)
CompilerEndIf
CompilerCase #PB_OS_MacOS
Shared SecuredPasswordCell.I
Shared VisiblePasswordCell.I
Protected Cell.I
Protected Password.S
Password = GetGadgetText(StringGadgetID)
If PeekS(CocoaMessage(0, CocoaMessage(0, CocoaMessage(0,
GadgetID(StringGadgetID), "cell"), "className"), "UTF8String"),
-1, #PB_UTF8) = "NSSecureTextFieldCell"
If VisiblePasswordCell = 0
SecuredPasswordCell = CocoaMessage(0, GadgetID(StringGadgetID),
"cell")
CocoaMessage(0, SecuredPasswordCell, "retain")
VisiblePasswordCell = CocoaMessage(0, CocoaMessage(0,
CocoaMessage(0, 0, "NSTextField alloc"), "initWithFrame:", 0),
"cell")
CocoaMessage(0, VisiblePasswordCell, "retain")
EndIf
CocoaMessage(0, GadgetID(StringGadgetID),
"setCell:", VisiblePasswordCell)
CocoaMessage(0, VisiblePasswordCell, "setStringValue:$", @Password)
CocoaMessage(0, GadgetID(StringGadgetID), "setNeedsDisplay:", #YES)
Else
If SecuredPasswordCell
CocoaMessage(0, GadgetID(StringGadgetID),
"setCell:", SecuredPasswordCell)
CocoaMessage(0, SecuredPasswordCell, "setStringValue:$", @Password)
CocoaMessage(0, GadgetID(StringGadgetID), "setNeedsDisplay:", #YES)
EndIf
EndIf
CompilerCase #PB_OS_Windows
Static PasswordChar
Static PasswordCharIsKnown
If PasswordCharIsKnown = #False
PasswordChar = SendMessage_(GadgetID(StringGadgetID),
#EM_GETPASSWORDCHAR, 0, 0)
PasswordCharIsKnown = #True
EndIf
If GetWindowLongPtr_(GadgetID(StringGadgetID),
#GWL_STYLE) & #ES_PASSWORD
SendMessage_(GadgetID(StringGadgetID), #EM_SETPASSWORDCHAR, 0, 0)
Else
SendMessage_(GadgetID(StringGadgetID), #EM_SETPASSWORDCHAR,
PasswordChar, 0)
EndIf
InvalidateRect_(GadgetID(StringGadgetID), 0, 1)
CompilerEndSelect
EndProcedure
OpenWindow(0, 270, 100, 250, 90, "Toggle password visibility")
StringGadget(0, 40, 20, 180, 20, "Test", #PB_String_Password)
CheckBoxGadget(1, 40, 55, 180, 25, "Show Password")
SetActiveGadget(0)
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
CocoaMessage(0, VisiblePasswordCell, "release")
CompilerEndIf
Break
Case #PB_Event_Gadget
If EventGadget() = 1
TogglePasswordVisibility(0)
SetActiveGadget(0); try comment this and toggle AFTER TYPING on Mac: will show both "passwords"
EndIf
EndSelect
ForEver
PureBasic itself uses different classes for the encrypted and unencrypted StringGadget and its cell. You may prove it with this example code:Piero wrote: Wed Feb 05, 2025 9:35 am I slightly modified your example and noticed that cocoa (initWithFrame) uses 2 gadgets too, am I right?
Code: Select all
OpenWindow(0, 270, 100, 250, 90, "Password modes")
StringGadget(0, 40, 20, 180, 20, "Test", #PB_String_Password)
StringGadget(1, 40, 50, 180, 20, "Test")
Msg$ = "Encryted StringGadget: " +
PeekS(CocoaMessage(0, CocoaMessage(0, GadgetID(0), "className"),
"UTF8String"), -1, #PB_UTF8) + #CR$
Msg$ + "Encryted cell: " +
PeekS(CocoaMessage(0, CocoaMessage(0, CocoaMessage(0,
GadgetID(0), "cell"), "className"), "UTF8String"), -1, #PB_UTF8) + #CR$
Msg$ + #CR$
Msg$ + "Unencryted StringGadget: " +
PeekS(CocoaMessage(0, CocoaMessage(0, GadgetID(1), "className"),
"UTF8String"), -1, #PB_UTF8) + #CR$
Msg$ + "Unencryted cell: " +
PeekS(CocoaMessage(0, CocoaMessage(0, CocoaMessage(0,
GadgetID(1), "cell"), "className"), "UTF8String"), -1, #PB_UTF8)
MessageRequester("StringGadget classes", Msg$)
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
Ooh, that's a great tip, thanks! (but my Cocoa is rusty to say the least
Code: Select all
;-TOP Dump Object Methods
; by mk-soft, 29.12.2019 - 06.10.2023, v1.09.1
Declare.s DumpObjectMethods(*Object, SuperLevel = 0, HidePrivate = #True, ShowEncoding = #False, FirstArgument = 2)
Structure ArrayOfMethods
i.i[0]
EndStructure
ImportC ""
class_copyMethodList(*Class, *p_methodCount)
; -> An array of pointers of type Method describing
; the instance methods implemented by the class
; Any instance methods implemented by superclasses are Not included
; You must free the array with free()
class_getName(*Class) ; -> UnsafePointer<Int8> -> *string
sel_getName(*Selector); -> const char *
method_getName(*Method) ; -> Selector
method_getTypeEncoding(*Method) ; -> const char *
method_getReturnType(*Method, *dst, dst_len) ; -> void
method_getNumberOfArguments(*Method) ; -> unsigned int
method_getArgumentType(*Method, index, *dst, dst_len) ; -> void
NSGetSizeAndAlignment(*StringPtr, *p_size, *p_align)
; -> const char *
; Obtains the actual size and the aligned size of an encoded type.
EndImport
; ----
Procedure.s GetArgumentType(*String)
Protected r1.s, arg.s, size.i, ofs.i
arg = PeekS(*String, -1, #PB_UTF8)
r1 + arg + " - "
If Left(arg, 1) = "^"
r1 + "A pointer to type of "
arg = Mid(arg, 2)
EndIf
Select arg
Case "c" : r1 + "A char "
Case "i" : r1 + "An int "
Case "s" : r1 + "A short "
Case "l" : r1 + "A long "
Case "q" : r1 + "A long long"
Case "C" : r1 + "An unsigned char "
Case "I" : r1 + "An unsigned int "
Case "S" : r1 + "An unsigned short "
Case "L" : r1 + "An unsigned long "
Case "Q" : r1 + "An unsigned long long "
Case "f" : r1 + "A float "
Case "d" : r1 + "A double "
Case "B" : r1 + "A C++ bool Or a C99 _Bool "
Case "v" : r1 + "A void"
Case "*" : r1 + "A character string (char *) "
Case "@" : r1 + "An object (whether statically typed Or typed id) "
Case "#" : r1 + "A class object (Class) "
Case ":" : r1 + "A method selector (SEL) "
Default:
NSGetSizeAndAlignment(*String, @size, @ofs)
r1 + "[" + Str(size) + " bytes]"
EndSelect
If Right(arg, 1) = "?"
r1 + "An unknown type (e.g. function pointer)"
EndIf
ProcedureReturn r1
EndProcedure
; ----
Procedure.s DumpObjectMethods(*Object, SuperLevel = 0, HidePrivate = #True, ShowEncoding = #False, FirstArgument = 2)
Protected result.s, r1.s, i, c, n, methodCount, Method.s
Protected *Class, *SuperClass, *Method, *Methods.ArrayOfMethods
Protected *String
*Class = object_getclass_(*Object)
If *Class
*String = AllocateMemory(1024)
r1 = PeekS(class_getName(*Class), -1, #PB_UTF8)
If SuperLevel
For i = 1 To SuperLevel
*SuperClass = class_getsuperclass_(*Class)
If *SuperClass
*Class = *SuperClass
r1 + " -> " + PeekS(class_getName(*Class), -1, #PB_UTF8)
Else
Break
EndIf
Next
EndIf
*Methods = class_copyMethodList(*Class, @methodCount)
r1 + #LF$ + #LF$ + "Count of Methods: " + methodCount + #LF$
result = r1 + #LF$
Debug r1
r1 = ""
For i = 0 To methodCount - 1
*Method = *Methods\i[i];
Method = PeekS(sel_getName(method_getName(*Method)), -1, #PB_UTF8)
If HidePrivate And Left(Method, 1) = "_"
Continue
EndIf
r1 + "Method " + Method + #LF$
If ShowEncoding
r1 + " * Encoding " + PeekS(method_getTypeEncoding(*Method), -1, #PB_UTF8) + #LF$
EndIf
method_getReturnType(*Method, *String, 1024)
r1 + " -- ReturnType = " + GetArgumentType(*String) + #LF$
c = method_getNumberOfArguments(*Method)
For n = FirstArgument To c - 1
method_getArgumentType(*Method, n, *String, 1024)
r1 + " -- Argument " + Str(n - FirstArgument + 1) + " = " + GetArgumentType(*String) + #LF$
Next
result + r1 + #LF$
Debug r1
r1 = ""
Next
r1 + "End Class" + #LF$
result + r1 + #LF$
Debug r1
If *Methods
free_(*Methods)
EndIf
FreeMemory(*String)
Else
r1 = "Object is nil" + #LF$
result = r1
Debug r1
EndIf
ProcedureReturn result
EndProcedure
; ****
If OpenWindow(0, 270, 100, 250, 90, "Password modes")
StringGadget(0, 40, 20, 180, 20, "Test", #PB_String_Password)
StringGadget(1, 40, 50, 180, 20, "Test")
Debug "StringGadget Password:"
DumpObjectMethods(GadgetID(0))
DumpObjectMethods(GadgetID(0),1)
DumpObjectMethods(GadgetID(0),2)
Debug "**************************************************************"
Debug ""
Debug "StringGadget default:"
DumpObjectMethods(GadgetID(1))
DumpObjectMethods(GadgetID(1),1)
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf