none
Draw Text from module subroutine error RRS feed

  • Question

  • Hi,

    I use Visual Basic .net 2017 to write a test program. In that program, I try to use subroutine from a module to draw text or graph but it seems to give me an error on LinearGradientBrush. Can somebody kindly help to solve this error and let me know?

    Here is the code:

    --------------------------------------------------------------------------------------------------

    Public Class Form1
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            drawOutput()
        End Sub
    End Class

    Imports System.Drawing.Drawing2D
    Module Module1
        Public Property ClientRectangle As PointF
        Public Sub drawOutput()

            Dim MyGraphics As Graphics = Form1.PictureBox1.CreateGraphics
            Dim MyBrush As New LinearGradientBrush(ClientRectangle, Color.Red,
            Color.Yellow, LinearGradientMode.Horizontal)
            Dim MyBrush1 As New LinearGradientBrush(ClientRectangle, Color.Green,
            Color.Blue, LinearGradientMode.Horizontal)

            Dim MyFont As New Font("Arial", 10.5, FontStyle.Regular)
            Dim MyFont1 As New Font("Cambria", 12, FontStyle.Regular)

            MyGraphics.DrawString("This is Arial Font!", MyFont, MyBrush, 40, 40)
            MyGraphics.DrawString("This is Cambria Font!!", MyFont1, MyBrush1, 40, 60)

        End Sub
    End Module

    --------------------------------------------------------------------------------------------------------

    I believe it should look really simple to someone who has some years of experience in vb.net unlike me.

    Please help!! 


    Tuesday, August 14, 2018 3:19 PM

Answers

  • Hi,

    You need to assign a value to ClientRectangle.

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Module1.ClientRectangle = New Rectangle(0, 0, 50, 10)
            drawOutput()
        End Sub

    Best Regards,

    Alex


    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Hi, Alex

    Thank you very much. It really works!! I really appreciate your reply.

    Best Regards,

    Jason

    I think you both should read what I wrote in my first post.

    What you are doing is fine as long as you can get it to work how you want.

    However, for the future you should learn to use a class with the data you need and then make class level routines to calc with that data. It makes it much easier to keep track of things in the code. You will see once you learn it. You can see you are already having problems keeping the variable sorted and working properly because you have some code in the form and some in the module and etc.

    I have an astronomy app you can see here:

      http://sandiasoftware.com/nightsky/NightSky.htm

    So you can tell me you have to do it this way and that and then I can tell you that you don't.

    In fact what you are doing is slowing things down and making it more difficult to code.

    But the important thing is can you do what you want and did you answer your question?

    If so what you are doing is fine continue on. Look over classes and try to start using them for the future.

    :)


    PS Since you already use the pic box ref you can also do this:

            Dim MyBrush As New LinearGradientBrush(Form1.Picturebox1.ClientRectangle,

           Color.Red, Color.Yellow, LinearGradientMode.Horizontal)

    Then you don't need your module property or the module.

    Or even better call the routine with the e.graphics from the picture1 paintevent then you don't need most of it. To call the paint event from a button clickevent you just Picturebox.Refresh.

    You want to write the code the way your mind works but I am showing you how vb works.

    PS Finally you should calculate the data in modual sub routines or classes but then draw that data in the control paint event (or sub routines that accept the paint event e.graphics drawing surface parameter) instead of using create graphics in other events like button click etc.

    Oh, in fact, your current code is not persisted, is it? ie if you cover the form with another form or application and then uncover it you lose your graphics and have to click the button again, right? Or resize the form...  whooaaa...

    If you are interested I will post an example.



    • Edited by tommytwotrain Wednesday, August 15, 2018 12:49 PM
    • Marked as answer by jasonfan2000 Thursday, August 16, 2018 3:38 AM
    Wednesday, August 15, 2018 11:31 AM

All replies

  • What is the error and what line does it occur on?

    Put all the code in the picturebox paint event and get it to work using e.graphics.

    Then if you must put it in the module.

    PS Where is ClientRectangle defined or why do you have it declared in the mod? That should be the pic box?



    Tuesday, August 14, 2018 4:27 PM
  • Hi,

    try to modify the code:

    Public Property ClientRectangle As Rectangle

    Best Regards,

    Alex


    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, August 15, 2018 1:28 AM
  • What is the error and what line does it occur on?

    Put all the code in the picturebox paint event and get it to work using e.graphics.

    Then if you must put it in the module.

    PS Where is ClientRectangle defined or why do you have it declared in the mod? That should be the pic box?



    Hi, Tommy

    Thank you for your reply. The error occurs on:

    Dim MyBrush As New LinearGradientBrush(ClientRectangle, Color.Red,
            Color.Yellow, LinearGradientMode.Horizontal)
            Dim MyBrush1 As New LinearGradientBrush(ClientRectangle, Color.Green,
            Color.Blue, LinearGradientMode.Horizontal)

    I know it works on the picturebox paint event. It is almost written in all VB .net sample programs in books you can find.

    The original program I've written did a lot of complicate astronomical calculations. I put them all in separate modules to make them easy to maintain.

    When the those values are calculated, they were passed to another module for drawing graphics. This is the reason that I MUST put those codes into a separate module. It cannot be done in the Picturebox of the main form itself.

    I've shorten the whole program codes here in order to make it looked simple and ask for help:)

    In fact, you can try it yourself. Create a vb project in the Visual studio 2017. Then in the main form, add a button called Button1. Paste the first part of code into Button1.click. And after that, add a Picturebox call Picturebox1 in this main form. 

    Then, add a module in to the project. Add the second part of code into it. You will see what happen. It only takes a minute or little longer.

    Thanks,

    Jason

    Wednesday, August 15, 2018 2:43 AM
  • Hi,

    try to modify the code:

    Public Property ClientRectangle As Rectangle

    Best Regards,

    Alex


    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Hi, Alex

    Thank you very much for your suggestion. The error of LinearGradientBrush has gone. But there's another error frustrating me instead when I've tried to run the codes.

    Something like:  System.ArgumentException: 'Rectangle '{X=0,Y=0,Width=0,Height=0}' width and height cannot be 0.

    I know the whole things work on the picturebox paint event. As I said, it is written in every VB .net sample programs in books you can find in the bookstores.

    But here I MUST do it in separate module because there were a lot of complicate astronomical calculations before these drawing graphic codes. I need to retrieve the values in order to get those values for drawing text. And if I select and fill in different values in other menu options in the main form, it should call another different module to draw graphics because they will drawing different types of graphics. This is what I try to do.

    I've shorten the whole program codes here in order to make it looked simple and ask for help:)

    In fact, you can try it yourself. Create a vb project in the Visual studio 2017. Then in the main form, add a button called Button1. Paste the first part of code into Button1.click. And after that, add a Picturebox call Picturebox1 in this main form. 

    Then, add a module in to the project. Add the second part of code into it. You will see what happen. It only takes a minute or little longer.

    Thanks,

    Jason

    Wednesday, August 15, 2018 2:54 AM
  • Hi,

    You need to assign a value to ClientRectangle.

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Module1.ClientRectangle = New Rectangle(0, 0, 50, 10)
            drawOutput()
        End Sub

    Best Regards,

    Alex


    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, August 15, 2018 3:11 AM
  • Hi,

    You need to assign a value to ClientRectangle.

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Module1.ClientRectangle = New Rectangle(0, 0, 50, 10)
            drawOutput()
        End Sub

    Best Regards,

    Alex


    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Hi, Alex

    Thank you very much. It really works!! I really appreciate your reply.

    Best Regards,

    Jason

    Wednesday, August 15, 2018 3:58 AM
  • Hi,

    I am glad you have got your solution, we appreciated you shared us your solution and mark it as an answer.

    Best Regards,

    Alex


    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, August 15, 2018 4:57 AM
  • Hi,

    You need to assign a value to ClientRectangle.

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Module1.ClientRectangle = New Rectangle(0, 0, 50, 10)
            drawOutput()
        End Sub

    Best Regards,

    Alex


    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Hi, Alex

    Thank you very much. It really works!! I really appreciate your reply.

    Best Regards,

    Jason

    I think you both should read what I wrote in my first post.

    What you are doing is fine as long as you can get it to work how you want.

    However, for the future you should learn to use a class with the data you need and then make class level routines to calc with that data. It makes it much easier to keep track of things in the code. You will see once you learn it. You can see you are already having problems keeping the variable sorted and working properly because you have some code in the form and some in the module and etc.

    I have an astronomy app you can see here:

      http://sandiasoftware.com/nightsky/NightSky.htm

    So you can tell me you have to do it this way and that and then I can tell you that you don't.

    In fact what you are doing is slowing things down and making it more difficult to code.

    But the important thing is can you do what you want and did you answer your question?

    If so what you are doing is fine continue on. Look over classes and try to start using them for the future.

    :)


    PS Since you already use the pic box ref you can also do this:

            Dim MyBrush As New LinearGradientBrush(Form1.Picturebox1.ClientRectangle,

           Color.Red, Color.Yellow, LinearGradientMode.Horizontal)

    Then you don't need your module property or the module.

    Or even better call the routine with the e.graphics from the picture1 paintevent then you don't need most of it. To call the paint event from a button clickevent you just Picturebox.Refresh.

    You want to write the code the way your mind works but I am showing you how vb works.

    PS Finally you should calculate the data in modual sub routines or classes but then draw that data in the control paint event (or sub routines that accept the paint event e.graphics drawing surface parameter) instead of using create graphics in other events like button click etc.

    Oh, in fact, your current code is not persisted, is it? ie if you cover the form with another form or application and then uncover it you lose your graphics and have to click the button again, right? Or resize the form...  whooaaa...

    If you are interested I will post an example.



    • Edited by tommytwotrain Wednesday, August 15, 2018 12:49 PM
    • Marked as answer by jasonfan2000 Thursday, August 16, 2018 3:38 AM
    Wednesday, August 15, 2018 11:31 AM
  • Hi, Tommy

    Thank you for your effort to answer my question.

    Quote what you've said:

    PS Since you already use the pic box ref you can also do this:

            Dim MyBrush As New LinearGradientBrush(Form1.Picturebox1.ClientRectangle,

           Color.Red, Color.Yellow, LinearGradientMode.Horizontal)

    Then you don't need your module property or the module.

    You are absolutely correct!! That may help to simplify the code and concept. Then I don't need to worry what value I shall assign to the ClientRectangle.

    I saw the astronomy app page you've mentioned. No doubt, it is a very professional app. Unfortunately, no program source that we can see and learn from your experience. I understand the app is written for commercial purpose. So it makes sense to me:)

    But, I believe you may have think away too far from my original question.

    As I said, I have shortened my code almost 85% in order to ask this LinearGradientMode error question. Using a button to trigger the drawing process is only to reduce the codes for this small testing program. That make it easier to ask you for help. I believe you won't spend time to read my whole long program for answering a simple syntax question:)

    Since you're so interested, I'd like to let you know how I did in my real program system.

    (1) When my vb program start, the main form appears. Then I select New from the menu bar input, an input form pops up. There is a Picturebox about 60% size inside the Main form.

    (2) On the input form, the user can input Date, time, locations and other info, etc.

    (3) After the Date, time and locations info were entered, then the user click ok button of the input form.

    (4) The program then calls the public subroutine of a separate module to calculate the planet position and math data, etc. Let's call this subroutine CALplanetPos.

    (5) Once CALplanetPos is done. Another public subroutine is called. The values just calculated were passed into that subroutine to draw graph in the Picturebox of the Main form. It is a fancy thing from what you may have expected. For example, first, the subroutine will draw 25 different boxes or squares in the Picturebox. Then, different values of Planets or stars will be filled into those 25 different boxes according to some rules. However, the coordinates of those values need to be assigned before they are actually put into the Picturebox. Those coordinates values or better refer to which box the planet should go for are all depends on the values computed in CALplanetPos. I believe they all should be done in the subroutine. Let's call it DRAWplanetPos.

    This is what the whole things done:)

    And, if I selected other options in the input form. A different subroutine will be called in order to calculate different things. And then another subroutine will be called in order to draw 34 circle in the Picturebox of the Main form. Planet values will be filled in then like I mentioned before.

    So, I believe the Drawing codes should be written separately in subroutines because they are two different types of graph.

    There's one thing I still have no idea how to do. I saw people did in a window program about 14 years ago. But it is probably done in C#. Here is what happen. The graph I am going to plot in the Picturebox of Main form may look too big to fit the size of the Picturebox itself. I plot it as a A4 size Picture but put it into a smaller size Picturebox. And if I use the mouse to click the Picture itself, the A4 size graph I've draw will move around within the Picturebox with a grey background. This way the user can see different part of the graph without zoom out. It is much like the Preview function in those Print programs of words, browser, etc. Currently I know how to make a graph moving by mouse in vb.net. But, I am just curious about what is the proper way to do in vb.net: drawing a fancy graph in A4 size within a Picturebox(or a canvas) that can move around inside the Picturebox to different position when mouse is clicking.  

    Thank you for your effort and advise again.

    Best Regards,

    Jason

     


    Thursday, August 16, 2018 3:37 AM
  • Jason,

    Well its a big subject. This will seem like a long post and is.

    "Using a button to trigger the drawing process is only to reduce the codes for this small testing program."

    Ok. I see. However, if the example changes the basic problem then its not a good example?

     "But, I am just curious about what is the proper way to do in vb.net: drawing a fancy graph in A4 size within a Picturebox(or a canvas) that can move around inside the Picturebox to different position when mouse is clicking.  "


    Yeah, hmm, well lets start by asking ourselves "what is A4 Size within a picturebox" ???

    You mean a4 proportions that are scaled (magnified) to fit inside the picturebox inside our application window inside the computer monitor screen.

    Have you ever drawn with CAD? This a4 size thing is similar to the mental block a beginner must overcome to understand CAD.

    We are drawing a known dimension from real life, a4 size, on an unknown size computer screen.

    In fact all we know about the computer screen is how many pixels it is and even then it does not tell us how many pixels is 1 meter on the computer monitor screen.

    So you ask "drawing a fancy graph in A4 size within a Picturebox(or a canvas) that can move around"

    Nothing is moving around. None of it actually exists. It is not a piece of wood inside a steel window frame. It is all undefined dots on a computer screen.

    It is an optical illusion and it is updated at the refresh rate of the monitor like 60 hertz (frames per second). The human eye can only detect up to about 30 fps.

    So the computer screen is being updated at a very high rate and each update lights the lights that is a dot color and that color may change with every update but the dot is constant. So whether we draw the dot blue or red is basically meaningless to the monitor. Only our eyes can tell it changed.

    So to make a long answer short the screen is updated or redrawn every refresh cycle anyway whether we are moving the picture around or not.

    So you are right about your thinking, you need to consider it all, and yes it will have an effect, but it may not be the one your would expect if you were building a bird house in real life.

    So now I am going to leave that confusion and just show you a CAD example of how to draw IMHO.

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/a95ea88e-588f-47c0-b8bc-a3a9fe8a7469/how-to-draw-to-scale-cad-with-gdi-and-vbnet?forum=vbgeneral

    And now did you follow what I mentioned about how to persist the image?

    Is your current method persiting? Do you understand what I am trying to say?

    That will be the first concern when drawing. You have to make sure the image will be there for each update of the monitor. The code you have shown in your shortened example is not there after clicking the button and then covering and uncovering the form etc. Correct?

    So the simple button example you show is no good?

    The clientrectangle problem you had is something else entirely. It is the rect used to make the linergradientbrush and can be any size rect. Alex was also correct that you never gave the variable a size, that was the error you got.

    What I am talking about is more. Not just how to make a lg brush.

    See if the cad example makes sense. See how it is drawn in the pic box paint event on the pic box e.graphics drawing surface?

    Now look carefully at the mouse wheel zooming and the RMB view port scrolling or dragging of the cad example.

    In the cad example the view port is determined in other events and saved in the ScaleRatio variable. So the app calcs the viewport ScaleRatio in some control event and saves it in the global variable ScaleRatio. Then when the application screen (window) needs updating the system calls the paint event and we draw the image at the size we have saved ScaleRatio.

    So just like we are saying, we calc, we save the values, we draw using the values that were saved.

    What I am suggesting is you make a class (not shown in the cad example) that is like a memory variable of all the things, julian day, lat, long, tz, planet orbit variables, current viewport, ... etc.

    We can make a class and all the variables can be in the class like a group of objects but. Now when we calc we take the planetvariables class with us to the planetcalc sub with just one clase variable currentplanetvariables, we do our calc, we update the vars, we pass currentplanetvariables, to drawplanets sub, drawjupiter sub, drawclock sub, drawsun sub...

    Well that is just one thing that classes do for us.

    Ok lets see how that goes down. Maybe it is just confusing everything at this point.

    BTW Jason, you can mark two posts as the answer if you want to mark Alex's response as the answer too.

    And Alex and other forum members feel free to join in the discussion of course.

    Thursday, August 16, 2018 10:27 AM
  • PS Jason,

    So using the paint event to make the initial drawing of the graph is one thing.

    You can redraw that entire graph each refresh if you like and eventually you will reach a (speed/time) limit where you have too much to draw for one (time) cycle.

    (But you can do like 100,000 drawing screen operations per second)

    So unless you have more to draw you can completely erase and redraw the viewport every paint event without problems in fact that is what I am recommending.

    And that's just to start the basic drawing.

    Then if you have some reason you can draw onto a permanent memory bitmap and then you can show that in the view port and scroll it as you say. If that is needed. YOu can also redraw the whole thing to scroll and zoom it.

    So I am saying first you just draw it in the paint event on a graphics surface. Then if require make sub routines you call with the graphics surface to draw on in the routine. And then even draw on a memory bitmap as required etc.

    Finally there is a chart control for graphs you might consider.


    Thursday, August 16, 2018 11:54 AM