Recent

Author Topic: Regarding the issue of debugging and monitoring the property values of UI contro  (Read 436 times)

yinhuajian

  • New Member
  • *
  • Posts: 16
procedure TForm1.Button1Click(Sender: TObject);
var
  str: String;
begin
  str := MaskEdit1.Text;
  MaskEdit1.Text := '1111';
end;

I want to monitor the value of MaskEdit1.Text in the above code. After adding breakpoints and starting debugging, I found that the IDE does not display the value of MaskEdit1.Text, but it can display the value of str. Why is this? Neither Ctrl+F5 nor Ctrl+F7 can observe the value of MaskEdit1.Text. Is it not possible to observe the property values of UI controls?

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12087
  • Debugger - SynEdit - and more
    • wiki
Unfortunately the compiler does not add this to the debug info.

That is: property with Getter method.
Code: Pascal  [Select][+][-]
  1. class TMaskEdit = ...
  2. property Text: TCatpion read GetText;
  3.  

Originally debuggers would not have been able to deal with that (gdb doesn't know the concept). But nowadays it would be possible, but it has not yet been fixed in FPC.

Mind, that the only way to get the value is to call that function. So if there was/is a way to call it, then that can have side effects. If that function makes changes to the state of the app, those changes will persist  (that also happens in Delphi and other languages).

But back to the problem...

The debugger can actually call function (if the compiler provided info). Unfortunately again the compiler only provides info for some functions.
=> GetText is not added by the compiler.

But for TMaskEdit, the compiler does add
Code: Pascal  [Select][+][-]
  1.   MaskEdit1.RealGetText()
which will get the text.

So you can:
- Menu: Tools > Options > Debugger > General: allow function calls. (this is a one time change)
- Add a watch "MaskEdit1.RealGetText()"  (not the braces "()")
- Tick "Allow function call" in the properties of that watch

And you should see the value.

yinhuajian

  • New Member
  • *
  • Posts: 16
Unfortunately the compiler does not add this to the debug info.

That is: property with Getter method.
Code: Pascal  [Select][+][-]
  1. class TMaskEdit = ...
  2. property Text: TCatpion read GetText;
  3.  

Originally debuggers would not have been able to deal with that (gdb doesn't know the concept). But nowadays it would be possible, but it has not yet been fixed in FPC.

Mind, that the only way to get the value is to call that function. So if there was/is a way to call it, then that can have side effects. If that function makes changes to the state of the app, those changes will persist  (that also happens in Delphi and other languages).

But back to the problem...

The debugger can actually call function (if the compiler provided info). Unfortunately again the compiler only provides info for some functions.
=> GetText is not added by the compiler.

But for TMaskEdit, the compiler does add
Code: Pascal  [Select][+][-]
  1.   MaskEdit1.RealGetText()
which will get the text.

So you can:
- Menu: Tools > Options > Debugger > General: allow function calls. (this is a one time change)
- Add a watch "MaskEdit1.RealGetText()"  (not the braces "()")
- Tick "Allow function call" in the properties of that watch

And you should see the value.
------------------------------------------------------------------------------------------------

Thank you for your explanation, that indeed helps me observe the `Text` value of `Edit1` during debugging. If I also want to observe the value of `UniQuery1.FieldByName('Name').AsString`, what should I do then?



Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12087
  • Debugger - SynEdit - and more
    • wiki
I don't have a db setup, so I can't test any that.

But "FieldByName" should be a function (at least the one I found in fcl-db).

You can try (again setting "allow function calls")
Code: Pascal  [Select][+][-]
  1. UniQuery1.FieldByName('Name').AsString()
'Name' can also be a variable.

It may not work, there are plenty of bits why it could fail. Starting with the relevant code is part of the FCL, which is likely compiled without debug info. It is possible debug info was added inside the project, but maybe, maybe not. Or maybe not enough...


You can try, FieldByName calls FindField(name), and that calls FFieldList.FindField(name)
But if FieldByName does not work, I don't expect those either.

If FieldByName does work, but GetAsString() does not, then you need to look through the sources of that.


If it does not, you need to find a way to add help to your code.

E.g.
TempStr := UniQuery1.FieldByName('Name').AsString;
or
TempField := UniQuery1.FieldByName('Name');

And watch that.


Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12087
  • Debugger - SynEdit - and more
    • wiki
Be aware though:

if it works, watching
UniQuery1.FieldByName('Name').AsString

may connect to the database and get the value. So it will show the value even if your app  had not yet retrieved it. And your app will be made to believe that it had done so, even though it did not. => And to the best of my knowledge this is the same if you debug/watch values like this in Delphi, or other languages.


If you call a function (including properties) in any debugger (of any / or of almost any language) then you maybe changing the behaviour of your app.

That is ok, if you know it, and if you know the side effects, and deal with that.

Bugs may not happen while the watch is active, or they may additionally happen.

I myself - a long long time ago - learned that painfully (wasting a few days of debugging), when I used (an older) Delphi to watch SomeControl.Handle => and that does create a handle for the control.
My code used FHandle. And that would crash, but only if not debugging. So I debugged and debugged, and the error did not happen, then I run without debugger, and the error was there.... And I didn't know why.

So if you get different behaviour in the debugger, while watching function call results => be aware. (again, most of the times watching the function is not a problem, but if you hit the case where it is ...)


 

TinyPortal © 2005-2018