Results 1 to 18 of 18

Thread: [RESOLVED] Using Windows 10, HDMI and monitors as an Embedded System

  1. #1

    Thread Starter
    Lively Member
    Join Date
    Aug 2019
    Posts
    119

    Resolved [RESOLVED] Using Windows 10, HDMI and monitors as an Embedded System

    I have a project that will be using the Odyssey X86J4105864 SBC. If I was working on an Embedded Platform, Micro, Display with a controller and a SPI Interface, it would be a normal project. However, this is not quite what this SBC presents. I would like to be able to access the Monitor Pixel by pixel through the HDMI Interface and from the Windows Graphics Controller.

    The goal here is to develop a HMI GUI (Human/Machine Interface) GUI. The project is to build a series of Gauges, Push Buttons, Stripchart Graphs, Slider Controls. 7-Segment LED Display and other Industrial Control images. If I had total control of the display I could accomplish anything I needed. Also, as the Windows Graphics Controller is powerful, I would also have access to all the fonts and other resources.

    An alternative method would be to obtain some libraries that worked with a specific language that had most of these capabilities already available. However, it would be very interesting to gain the knowledge to be able to totally access a PC Monitor as if it was an embedded display.

    I am looking for any assistance for this project, thanks Y'All

  2. #2
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Using Windows 10, HDMI and monitors as an Embedded System

    You can have access to every pixel, if you want, so that isn't an issue, e.g. use a borderless form to fill the monitor, assign a bitmap to fill the form, and then you can access the pixels of the bitmap, either directly using the bitmap object (which is slow), or by maintaining an array in memory that maps to the pixels so you can update the memory quickly and refresh the bitmap from that memory.

    There is no need to try to do things at a controller level. Especially if you say you would like to use an HMI library. No library is going to bypass windows to work at a controller level for a given specific hardware interface.

    If VB would not be a good choice, then C# seems like it would also not be a good choice, as they are two sides of the same coin.
    If your programming preference is C# over VB, then that is reasonable, but it has nothing to do with the ability of the language to do the job.

    I'm sure there are plenty of choices for libraries out there. Just doing a search for "gui gauge library" and this was one of the first links hit. Looking at the example images, perhaps some of those example are similar to the type of controls you would like to have.
    Also, since it is at least Free to get started, it wouldn't cost you anything but time to try it out.
    Last edited by passel; Jun 11th, 2020 at 01:00 PM.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  3. #3

    Thread Starter
    Lively Member
    Join Date
    Aug 2019
    Posts
    119

    Re: Using Windows 10, HDMI and monitors as an Embedded System

    Quote Originally Posted by passel View Post
    You can have access to every pixel, if you want, so that isn't an issue, e.g. use a borderless form to fill the monitor, assign a bitmap to fill the form, and then you can access the pixels of the bitmap, either directly using the bitmap object (which is slow), or by maintaining an array in memory that maps to the pixels so you can update the memory quickly and refresh the bitmap from that memory.

    There is no need to try to do things at a controller level. Especially if you say you would like to use an HMI library. No library is going to bypass windows to work at a controller level for a given specific hardware interface.

    If VB would not be a good choice, then C# seems like it would also not be a good choice, as they are two sides of the same coin.
    If your programming preference is C# over VB, then that is reasonable, but it has nothing to do with the ability of the language to do the job.

    I'm sure there are plenty of choices for libraries out there. Just doing a search for "gui gauge library" and this was one of the first links hit. Looking at the example images, perhaps some of those example are similar to the type of controls you would like to have.
    Also, since it is at least Free to get started, it wouldn't cost you anything but time to try it out.
    I may not have explained myself accurately. If I had a Programming Library, then of course I would not interfere with the OS usage of the Display Controller. If I write a bitmap to a blank screen that composed of all the "Static" features of the display image such as the outline of the Gauges, this would be great and easy to perform. After that though, I would like to have direct control of such things as numeric values, which would be dynamic. Continuously updating the bitmap in its entirety and rewriting it would not be efficient.

    Using a set of libraries would be an easier solution but I would then be restricted to the library itself. If I had direct control of the Windows Display Controller, I would be master of everything (a little power complex there, sorry). This would be a very useful function to have in any language.

    As an embedded solution, I would have two arrays, one would comprise the elements 0,1,2,3...9 and would be a pointer to the second array that would be a small bitmap of what I wanted to write. Because I can compose any bitmap (within the pixel matrix size) I have essentially the ability to write this small bitmap anywhere...and fast. This arrangement would be perfect for what I would like to do inside Windows. After all, Windows has an excellent controller and a great port (HDMI) and a large low cost PC Monitor...all the hardware I need. All I need now is a programming language which could be anything, Basic, C,C#, Python, it does not matter.

    I hope I have explained myself better this time...I would love some comments to provide this solution. Thanks Y'All.

  4. #4
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Using Windows 10, HDMI and monitors as an Embedded System

    I think you've explained yourself well enough. And I'm saying that all you want to do is possible, with the exception of needing to have "direct control of the Windows Display Controller".

    I'm saying you don't need that.

    I've worked on several embedded systems over the years, and the early ones provided a memory buffer that represented the pixel frame buffer, and you could write code that transferred blocks of values from your program to memory to copy preset images into the frame buffer.
    This is essentially a bitblt API call, done manually.

    If that is what you want to do, then that is still possible, which is what I've said from the beginning. You can access the bitmap as an array of bytes, or longs, or however you want to map it, so you can write routines to transfer blocks of pixel values to the bitmap using those arrays.

    But I'm also saying, that needing to do that is usually not necessary. You can create multiple small bitmaps of whatever size you want, and then draw those small bitmaps into any location within the overall bitmap to update dynamic portions of the image, without having to redraw the whole image.

    I see I lost my link when I posted above, so the link to the gauges library wasn't included above. I've fixed that.
    I'm saying that if you have the time, and the library looks interesting, you can investigate it without cost to see if it might meet your needs.

    But, if you're already of the mindset that you would like to treat the screen as an array of pixels and be able to update those pixels manually by simply addressing them, then you can do that. Both boopsboops and I have posted code (slightly different approaches) that allows you do address an image quickly as an array, so you have that option if that is what you want.

    Out of curiosity, what resolution do you expect your "embedded" display to be, e.g. 1920x1080, or 3840x2160, for instance.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  5. #5

    Thread Starter
    Lively Member
    Join Date
    Aug 2019
    Posts
    119

    Re: Using Windows 10, HDMI and monitors as an Embedded System

    Quote Originally Posted by passel View Post
    I think you've explained yourself well enough. And I'm saying that all you want to do is possible, with the exception of needing to have "direct control of the Windows Display Controller".

    I'm saying you don't need that.

    I've worked on several embedded systems over the years, and the early ones provided a memory buffer that represented the pixel frame buffer, and you could write code that transferred blocks of values from your program to memory to copy preset images into the frame buffer.
    This is essentially a bitblt API call, done manually.

    If that is what you want to do, then that is still possible, which is what I've said from the beginning. You can access the bitmap as an array of bytes, or longs, or however you want to map it, so you can write routines to transfer blocks of pixel values to the bitmap using those arrays.

    But I'm also saying, that needing to do that is usually not necessary. You can create multiple small bitmaps of whatever size you want, and then draw those small bitmaps into any location within the overall bitmap to update dynamic portions of the image, without having to redraw the whole image.

    I see I lost my link when I posted above, so the link to the gauges library wasn't included above. I've fixed that.
    I'm saying that if you have the time, and the library looks interesting, you can investigate it without cost to see if it might meet your needs.

    But, if you're already of the mindset that you would like to treat the screen as an array of pixels and be able to update those pixels manually by simply addressing them, then you can do that. Both boopsboops and I have posted code (slightly different approaches) that allows you do address an image quickly as an array, so you have that option if that is what you want.

    Out of curiosity, what resolution do you expect your "embedded" display to be, e.g. 1920x1080, or 3840x2160, for instance.
    I am unclear about something, please advise if I have it wrong:
    1) I create a bitmap image of all the "Static" parts of the display (The Static Bitmap) such as titles and names of the gauges, but no dynamic variables like numerical values of Pressure for instance
    2) A separate functions gathers information from Sensors, such as pressure. I then overwrite the Static Bitmap areas with the numeric values and then re-write the whole "Static Bitmap", only this time the Numeric Values are included.
    3) This means that I have to write the entire Bitmap every time a variable changes.
    4) Would it not be better to write the static Bitmap and then just write the dynamic variables as they change...I need to know how to do this. I realize that the Display Controller can write 4K video at 60fps, so I am probably fussing about nothing.

    The display resolution could be as low as 1024 x 768 as there really isn't a need for anything better...let me know if I have things correct because your comment...

    "But I'm also saying, that needing to do that is usually not necessary. You can create multiple small bitmaps of whatever size you want, and then draw those small bitmaps into any location within the overall bitmap to update dynamic portions of the image, without having to redraw the whole image". <<<I don't see how you can do this. You must write the whole bitmap again, right?

  6. #6
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Using Windows 10, HDMI and monitors as an Embedded System

    Do you have some version of Visual Studio installed?
    If so, then perhaps we could point you to examples, or post examples.
    (I'm thinking of a quick example with a fixed background image, with perhaps 800 scrolling digit windows scattered about the window, to be updated dynamically, as a simple exercise).

    Generally, I have data coming from a lot of different sources, so have background threads receiving and processing the data and placing the results in a shared area, like a static class, or a module in VB. Since the data can be coming from a lot of different sources, and at whatever speed they choose, technically data can be changing hundreds or thousands of times per second.

    As for displaying that data, I usually use a timer that is running at a fixed, slower speed, say 10 hz or 20 hz, and it will update the GUI at that rate. So, while I may have three flight controller computers, sending data at 100hz each, a graph that is showing the last 30 seconds of some piece of that data continuously, will be updated at the slower rate, but you'll see all the data scrolling by, it is just that graph may be shifting 5 or 10 data points at a time.

    I have to go away from the computer for awhile, so I guess I'll have to stop here.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  7. #7

    Thread Starter
    Lively Member
    Join Date
    Aug 2019
    Posts
    119

    Re: Using Windows 10, HDMI and monitors as an Embedded System

    Quote Originally Posted by passel View Post
    Do you have some version of Visual Studio installed?
    If so, then perhaps we could point you to examples, or post examples.
    (I'm thinking of a quick example with a fixed background image, with perhaps 800 scrolling digit windows scattered about the window, to be updated dynamically, as a simple exercise).

    Generally, I have data coming from a lot of different sources, so have background threads receiving and processing the data and placing the results in a shared area, like a static class, or a module in VB. Since the data can be coming from a lot of different sources, and at whatever speed they choose, technically data can be changing hundreds or thousands of times per second.

    As for displaying that data, I usually use a timer that is running at a fixed, slower speed, say 10 hz or 20 hz, and it will update the GUI at that rate. So, while I may have three flight controller computers, sending data at 100hz each, a graph that is showing the last 30 seconds of some piece of that data continuously, will be updated at the slower rate, but you'll see all the data scrolling by, it is just that graph may be shifting 5 or 10 data points at a time.

    I have to go away from the computer for awhile, so I guess I'll have to stop here.
    Fantastic...If I knew how to do this, problem solved...I cant wait for your return, thank you so much. Yes I do have Visual Studio installed, latest version, currently set up for VB

  8. #8
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Using Windows 10, HDMI and monitors as an Embedded System

    Since I'm both busy and lazy, I guess I'm not working on any new examples as higher priority tasks beckon.

    But, I'll give you three examples, somewhat related, that you can look at in the mean time.
    The first two were originally posted in response to questions on another forum, and were later posted here in response to other questions. There were written back in 2012, and the posts linked to will describe them in more detail.

    VB_Drawing_Demo drawing some parts of an ADI as a graphics example for someone.
    AnalogClockReadingTest Example of analog clock, for possibly teaching child to read an analog clock.

    I had another question from someone, but not on a forum, about the ability to take a digital photograph of a panel, and then being able to have code animate the needles on the gauges in a program. I said that was fairly simple, and as a quick example, grabbed an image of a panel with a few gauges on it and added them as resources to the Analog clock program above, and modified the code of that example to move the needles on the gauges.

    This was about four years ago. I didn't post that example anywhere before, so I though I would clean it up, and maybe expanded it to show it manipulating more than five gauges, but decided I don't have the time at the moment, so may as well post it as is.

    It doesn't work the way you want, where you maintain a background image and don't redraw it. The code was written to scale the image to fit the form, so if you resize the form, the panel resizes as well, so we redraw the background panel each time. But, it wouldn't have to be.

    Even so, since the code updates the drawing in "layers", you still see how the larger background panel bitmap, is drawn on by drawing smaller bitmaps on top of it.
    1. The background panel image is drawn first and still has the needles on it that were captured in the photo.
    2. A smaller bitmap that just contains the face of the gauge without a needle, is drawn over the face of each gauge to "erase" the existing needle.
    3. Last a needle image, that has been rotated to the desired reading, is drawn on the face.

    In this case, the five gauges happen to be essentially the same, with two of the five being larger versions of the gauge.
    So, I created the blank face from one of the larger gauges, manually removing the needle in Microsoft's Paint.
    I also tried to recreate the needle from that image in a third image so I had a needle that could be rotated and drawn on the face.

    Since the three smaller gauges are essentially the same as the two larger images, I just used the same "blank face" image and "needle" image to draw on the smaller gauges, they are just resized by a transform when drawing them on the smaller gauges, so they fit.
    I changed the "click here" box, so that you can also drag on that box to rotate the needles, rather than just have them jump to a random position. That way you can see if they update quickly on your machine.

    I'll attach that example here.
    Attached Files Attached Files
    Last edited by passel; Jun 15th, 2020 at 07:06 AM.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  9. #9

    Thread Starter
    Lively Member
    Join Date
    Aug 2019
    Posts
    119

    Re: Using Windows 10, HDMI and monitors as an Embedded System

    Quote Originally Posted by passel View Post
    Since I'm both busy and lazy, I guess I'm not working on any new examples as higher priority tasks beckon.

    But, I'll give you three examples, somewhat related, that you can look at in the mean time.
    The first two were originally posted in response to questions on another forum, and were later posted here in response to other questions. There were written back in 2012, and the posts linked to will describe them in more detail.

    VB_Drawing_Demo drawing some parts of an ADI as a graphics example for someone.
    AnalogClockReadingTest Example of analog clock, for possibly teaching child to read an analog clock.

    I had another question from someone, but not on a forum, about the ability to take a digital photograph of a panel, and then being able to have code animate the needles on the gauges in a program. I said that was fairly simple, and as a quick example, grabbed an image of a panel with a few gauges on it and added them as resources to the Analog clock program above, and modified the code of that example to move the needles on the gauges.

    This was about four years ago. I didn't post that example anywhere before, so I though I would clean it up, and maybe expanded it to show it manipulating more than five gauges, but decided I don't have the time at the moment, so may as well post it as is.

    It doesn't work the way you want, where you maintain a background image and don't redraw it. The code was written to scale the image to fit the form, so if you resize the form, the panel resizes as well, so we redraw the background panel each time. But, it wouldn't have to be.

    Even so, since the code updates the drawing in "layers", you still see how the larger background panel bitmap, is drawn on by drawing smaller bitmaps on top of it.
    1. The background panel image is drawn first and still has the needles on it that were captured in the photo.
    2. A smaller bitmap that just contains the face of the gauge without a needle, is drawn over the face of each gauge to "erase" the existing needle.
    3. Last a needle image, that has been rotated to the desired reading, is drawn on the face.

    In this case, the five gauges happen to be essentially the same, with two of the five being larger versions of the gauge.
    So, I created the blank face from one of the larger gauges, manually removing the needle in Microsoft's Paint.
    I also tried to recreate the needle from that image in a third image so I had a needle that could be rotated and drawn on the face.

    Since the three smaller gauges are essentially the same as the two larger images, I just used the same "blank face" image and "needle" image to draw on the smaller gauges, they are just resized by a transform when drawing them on the smaller gauges, so they fit.
    I changed the "click here" box, so that you can also drag on that box to rotate the needles, rather than just have them jump to a random position. That way you can see if they update quickly on your machine.

    I'll attach that example here.
    The anticipation is killing me...downloading now. Chat later, thanks
    OK, installed and ran...perfect. I will examine the code and see how to apply this to my project...thanks, wonderful solution
    Last edited by BasicBasic; Jun 15th, 2020 at 08:02 AM.

  10. #10
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Using Windows 10, HDMI and monitors as an Embedded System

    Just be aware because the gauge example used the existing clock code, there is a lot of extraneous things in there.
    I was planning on paring that down in a new project, specific to doing just the gauge manipulation, but realized that I wouldn't get around to it for days, so just posted the mess.
    Perhaps it will be clear enough for you to extract what you need or want to use.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  11. #11

    Thread Starter
    Lively Member
    Join Date
    Aug 2019
    Posts
    119

    Re: Using Windows 10, HDMI and monitors as an Embedded System

    Quote Originally Posted by passel View Post
    Just be aware because the gauge example used the existing clock code, there is a lot of extraneous things in there.
    I was planning on paring that down in a new project, specific to doing just the gauge manipulation, but realized that I wouldn't get around to it for days, so just posted the mess.
    Perhaps it will be clear enough for you to extract what you need or want to use.
    What I am not clear about yet is how Write the Background image (static bitmap) and then know where to wtite the Variable Bitmap stuff. In the embedded world, I would know where the Bottom Left corner of the Variable Bitmap[000] would be and then I would write bits to the location. I would then index to location Variable Bitmap [001] and write the next row of bits. I can visualize how that would work. What I cant imaging (right now) is how to do that in Windows. If you can just explain (with a small code fragment), I might get the Eureka Moment.

  12. #12
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Using Windows 10, HDMI and monitors as an Embedded System

    Windows uses the upper left corner, the Y axis starts with 0 at the top, and increases going down the window.
    So, when you draw a image on another image, you typically specify the upper left corner of the image.

    But for flexibility, I'll often use the center of the image being drawn as the reference point for that image, so the center of the image is drawn at a point of the background image.
    And rather than do a lot of calculation, I'll use the built in transformation matrix to offset the (0,0) point of the coordinate system. That way, the upper-left corner specified, and the height and width values of what is being drawn never has to change.
    You just change the coordinate system to center on where you want the image, and then just draw it with the fixed relative coordinates.

    I don't know if you tried the first link, i.e. the VB_Drawing_Demo one.
    That code has a step mode that you can enable, and you can see the results of the various drawing commands being applied to the drawing, with an explanation of what the code is doing at each step. But, even more illustrative, is the fact that the user interface is fully active, so that you can input pitches and rotations to the instrument, and see what affect they have at each step of the drawing process interactively.

    Take a look at that, and I'll see about doing a quick, small demo, of one way of drawing an image on a background image, with as little code as possible.
    Last edited by passel; Jun 16th, 2020 at 01:06 PM.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  13. #13
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Using Windows 10, HDMI and monitors as an Embedded System

    Ok, a simple quick example.
    Just paste into a new project and run, no controls required.
    In the form load, it will create a large bitmap, then fill it with random translucent ellipses, and then set the background image of the form to that bitmap.
    It will then create a small bitmap to use as our example bitmap to be drawn on the larger bitmap (a simple yellow circle).
    Since we don't specify a color or clear the bitmap, the bitmap is created with all the pixels having a value of (0,0,0,0), so are transparent black, i.e. just transparent).

    So, when we draw that bitmap on the larger bitmap, only the yellow circle will show up, the other pixels around the yellow circle in the bitmap are transparent.

    Now, when ever you click on the form, the mouse position is saved, the form is invalidated, so the paint event occurs.
    Before you get the Paint event, the background image is restored in the backbuffer (we set doublebuffered to true), so any drawing done in previous paint events is already gone, i.e. we don't need to clear anything.

    The paint event code simply moves the (0,0) coordinate of the drawing area to where the mousedown occurred.
    It then draws the bitmap with the yellow circle, with a (-50,-50 :top left coordinate), so that the 100x100 sized bitmap is centered on (0,0).

    Just click around the form until you get bored with the fact that that is all it does.
    Code:
    Public Class Form1
    
      Private rand As New Random
      Private smallBitMap As New Bitmap(100, 100)
      Private mLoc As Point   'mousedown position
    
      Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        Dim bigBitMap As New Bitmap(2048, 1080)
        Dim g As Graphics = Graphics.FromImage(bigBitMap)
        Dim r As New Rectangle(0, 0, 100, 100)
        Dim c As Color
        Dim sbrush As New SolidBrush(Color.Red)
    
        For i As Integer = 1 To 500
          c = Color.FromArgb(160, rand.Next(255), rand.Next(255), rand.Next(255))
          r.X = rand.Next(2000)
          r.Y = rand.Next(1000)
          r.Width = 50 + rand.Next(200)
          r.Height = 50 + rand.Next(200)
          sbrush.Color = c
          g.FillEllipse(sbrush, r)
        Next
        BackgroundImage = bigBitMap
        sbrush.Dispose()
        g.Dispose()
    
        g = Graphics.FromImage(smallBitMap)
        g.FillEllipse(Brushes.Yellow, New Rectangle(0, 0, 100, 100))
        g.Dispose()
        DoubleBuffered = True
      End Sub
    
      Private Sub Form1_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
        mLoc = e.Location
        Invalidate()
      End Sub
    
      Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        With e.Graphics
          .TranslateTransform(mLoc.X, mLoc.Y)
          .DrawImage(smallBitMap, -50, -50, 100, 100)
          .ResetTransform()
        End With
      End Sub
    End Class
    Before you get too bored, you could add the following event handler to possibly entertain for a few more seconds, (i.e. dragging a bitmap around over the background bitmap)
    Code:
      Private Sub Form1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
        If e.Button = Windows.Forms.MouseButtons.Left Then
          mLoc = e.Location
          Refresh()
        End If
      End Sub
    Last edited by passel; Jun 15th, 2020 at 02:15 PM.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  14. #14
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Using Windows 10, HDMI and monitors as an Embedded System

    As I was closing down the above test project, I decided to add a bit more for the exercise/entertainment.
    It is probably of no use to what you want to do, but I figure I'll post it for what its worth.

    I added a small class to hold a bitmap and a few other values, to hold an instance of the "small bitmap" object with the circle in it.
    I also added a list, that can hold instances of that class, so multiple small bitmaps can be added to the example, not just the one in the original.
    When you click with the right mouse button, it will create a new instance of the bitmap, with a different color for the circle. It also prints a number in the bitmap image, in both white and black with a slight offset, so that the number will show up against a dark or light circle color.

    The small bitmaps are drawn in the order they are added to the list, so the last item in the list is topmost in the z-order.
    A loop was added to the mouseDown to search the list in reverse (top to bottom) to find the first small bitmap that was clicked in, in cases where they overlap.

    If no existing small bitmap circle is clicked, then the last one clicked on is moved to where you clicked, as in the previous example. If you do click on one, then it is moved, and can be dragged, as in the previous example.

    Since the mLoc no longer had a purpose in this example, I decided to use it as a overall (0,0) reference, i.e. when the small bitmaps are drawn, they are drawn relative to (0,0) which would normally be the upper left corner.
    But by dragging with the middle mouse button, you can change the value of mLoc, and mLoc is used to move the (0,0) coordinate reference at the beginning of the Paint, so all small bitmaps will be drawn relative to the current mLoc position, i.e. if you drag with the middle mouse button, all the smaller bitmaps will move together relative to the motion of the mouse.

    On my machine, I can click the right mouse button a hundred times or more, creating a hundred or more small bitmaps, scattered around the form. I can select any one to move it around, or move all of them together using the middle mouse button, and I don't see any real slowdown in the drawing speed. Perhaps other machines may be slower and start bogging down sooner.

    In any case, if you want to create a hundred or more small bitmaps, and then reposition them (all or one doesn't really make a difference in draw speed, since they all are redrawn regardless with this example), and see if there is significant lag or not in your case. Especially if you get your SBC and can run it there.
    Code:
    Public Class Form1
    
      Private rand As New Random
      Private mLoc As Point   'mousedown position
      Private itemList As New List(Of ItemBitMap)
      Private currentItem As ItemBitMap
    
      Private Class ItemBitMap
        Public Loc As Point
        Public Size As Size = New Size(100, 100)
        Public Picture As New Bitmap(100, 100)
    
        Public Sub draw(g As Graphics)
          drawAt(g, Loc.X, Loc.Y)
        End Sub
    
        Public Sub drawAt(g As Graphics, x As Integer, y As Integer)
          Loc.X = x
          Loc.Y = y
          Dim gc As Drawing2D.GraphicsContainer
          gc = g.BeginContainer
          g.TranslateTransform(x, y)
          g.DrawImage(Picture, -50, -50, 100, 100)
          g.EndContainer(gc)
        End Sub
      End Class
    
      Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        Dim bigBitMap As New Bitmap(2048, 1080)
        Dim g As Graphics = Graphics.FromImage(bigBitMap)
        Dim r As New Rectangle(0, 0, 100, 100)
        Dim c As Color
        Dim sbrush As New SolidBrush(Color.Red)
    
        For i As Integer = 1 To 500
          c = Color.FromArgb(160, rand.Next(255), rand.Next(255), rand.Next(255))
          r.X = rand.Next(2000)
          r.Y = rand.Next(1000)
          r.Width = 50 + rand.Next(200)
          r.Height = 50 + rand.Next(200)
          sbrush.Color = c
          g.FillEllipse(sbrush, r)
        Next
        BackgroundImage = bigBitMap
        sbrush.Dispose()
        g.Dispose()
    
        Dim item As New ItemBitMap
        g = Graphics.FromImage(item.Picture)
        g.FillEllipse(Brushes.Yellow, New Rectangle(0, 0, 100, 100))
        g.Dispose()
        itemList.Add(item)
        currentItem = item
        DoubleBuffered = True
      End Sub
    
      Private Sub Form1_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
    
        Dim relPos As Point = e.Location - New Size(mLoc.X, mLoc.Y)
    
        If e.Button = Windows.Forms.MouseButtons.Left Then
          For j As Integer = itemList.Count - 1 To 0 Step -1
            With itemList(j)
              If New Rectangle(.Loc - New Size(50, 50), .Size).Contains(relPos) Then
                Dim dx As Integer = relPos.X - .Loc.X
                Dim dy As Integer = relPos.Y - .Loc.Y
                Dim r As Integer = dx * dx + dy * dy
                If r < 50 * 50 Then
                  currentItem = itemList(j)
                  Exit For
                End If
              End If
            End With
          Next
          currentItem.Loc = relPos
          Invalidate()
    
        ElseIf e.Button = Windows.Forms.MouseButtons.Right Then
          Dim item As New ItemBitMap
          Using g As Graphics = Graphics.FromImage(item.Picture)
            Using sb As New SolidBrush(Color.FromArgb(255, rand.Next(255), rand.Next(255), rand.Next(255)))
              g.FillEllipse(sb, New Rectangle(0, 0, 100, 100))
            End Using
            g.TranslateTransform(10, 30)
            g.ScaleTransform(2, 2)
            g.DrawString(itemList.Count.ToString, Me.Font, Brushes.White, -1, -1)
            g.DrawString(itemList.Count.ToString, Me.Font, Brushes.Black, 0, 0)
          End Using
          itemList.Add(item)
          currentItem = item
          currentItem.Loc = relPos
          Invalidate()
        End If
    
      End Sub
    
      Private Sub Form1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
        Static lpos As Point
    
        If e.Button = Windows.Forms.MouseButtons.Left Then
          Dim relPos As Point = e.Location - New Size(mLoc.X, mLoc.Y)
    
          currentItem.Loc = relPos
          Refresh()
    
        ElseIf e.Button = Windows.Forms.MouseButtons.Middle Then
          mLoc += New Size(e.X - lpos.X, e.Y - lpos.Y)
          Invalidate()
        End If
        lpos = e.Location
      End Sub
    
      Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        e.Graphics.TranslateTransform(mLoc.X, mLoc.Y)
        For Each item As ItemBitMap In itemList
          item.draw(e.Graphics)
        Next
      End Sub
    End Class
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  15. #15

    Thread Starter
    Lively Member
    Join Date
    Aug 2019
    Posts
    119

    Re: Using Windows 10, HDMI and monitors as an Embedded System

    Back again:
    I looked at he Drawing Project but found the code far beyond my current capabilities. My project should be a simple one si I will outline it here and I will tell you the ignorance aspects that needs filling in:
    * The Static Bitmap: There will be a few of these depending on what the user wished to look at. I have used FORMS before and was planning to use them as a Place Holder for any Window GUI needed.
    * If I write a Bitmap Static Image, say a series of 7-Segment Displays with borders. All I will need to do then is have a Sub that I can pass the location of a Bitmap Image of a Number where I would make 0-9 and use an array to locate the correct image to be written by the Sub.
    If I can accomplish this small task, I could be really dangerous.
    Because VB is a little wordy, I sometimes cannot see the wood from the trees and follow what is going on. I never could understand other peoples code.

    Ignorance Next:
    I apologize is I seem to lack the knowledge to ask the questions correctly, but this is the pain of being a novice.
    1) I will create the Static Image at the correct resolution, say 1024 x 768
    2) I will create an array of Number Images 0-9 and some Control Characters
    3) I need to write the static image at the correct location (0,0) and then write the Dynamic Images where they need to go. Foe a test, I wouild count from 0-9 and then repeat...I would be so happy when I can do that.
    4) Would I place a boolean test not to write the Static Image after it was written once. If a dynamic image was a circle, it would need the center of the circle filled in or the background would be seen through the circle, right
    5) I noticed that there was an import Library called "System.Drawing.Drawing2D". Is this a standard Library of one generated by the programmer
    6) Are there any Graphic Libraries available fo VB or will I have to build everything I need, from scratch
    7) As I said, I am using the Odyssey SBC from Seeed Technology. How do I pass Dynamic Data into the VB program. Do I use some kind of External File that I can write too and then have VB read the data. How do I avoid collisions. I believe that the Odyssey has a serial port to communicate out to an Arduino. I will have to read-upon how that is done.

    Icant tell you how much I appreciate your help...thanks.
    Last edited by BasicBasic; Jun 26th, 2020 at 12:43 PM.

  16. #16
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Using Windows 10, HDMI and monitors as an Embedded System

    1. Ok. If you have different static bitmaps that you want to display, then you could just set the BackgroundImage of the form to that image, when you change it, rather than draw it. That will make the updating easier, i.e. you won't have to redraw the background in the paint event, and all the foreground dynamic parts will have been erased waiting for you to update them inside the Paint Event.

    You could also load each static bitmap in its own picturebox and have only the one that is currently active visible. Again, update all the dynamic portions in each paint event.

    2. Ok. In the example I'm posting, I loaded a single bitmap with the 10 digits in it, and when the example loads, I divided the single bitmap into 10 smaller single digit bitmaps. I did this to save me the time of having to create 10 single bitmaps in a paint program offline, but in the end uses multiple small bitmaps as you would.

    3. As mentioned in 1 (above), you have options. If you want to only draw the static image once, to avoid complications you would need to maintain a bitmap image in memory to work with, as your static buffer. But if would be easier to take advantage of the built in capability of the Picture or Form to maintain that static image by assigning the image to the Background Image of the Form, or the Image property of a picturebox. That way, whenever you invalidate the control, the Paint event is triggered and you have a fresh copy of the static image to draw on, without the previous things you've drawn on the background. You just draw all the dynamic stuff in the paint event and you're done.

    If you don't want to do it this way, and would rather maintain a static image in memory, and update it ad hoc, perhaps in parts without redoing all the dynamic stuff every pass, then that is another approach that can be done, but would take more explanation.

    4. Redrawing boolean already covered above. Not needed if you assign the image to the control.
    As for the dynamic image being a circle and showing the background through the circle, it depends on the image format. In order to see the background within the rectangle of the image, the image would have to contain transparent pixels, i.e. the pixels are defined by four values, alpha, red, green and blue values. if the alpha is 0, then the pixel will not be drawn so you would see the pixel "underneath". If the Alpha is 255 the color is opaque so you see the color from your image. Any value from 1 to 254, and you see a mixture of the pixel from the image and the pixel "underneath", 1 is almost all of the underneath pixel and 254 is almost all of the image pixels, and 128 would be an even mixture of the two.

    5. System.Drawing.Drawing2D is a standard .Net library so available in all the .Net versions.

    6. I'm sure there are many graphic libraries available. I have only used what is built into .Net, so accessible from VB and C# and other languages using the .Net Frameworks.

    7. If the Dynamic Data isn't being generated by the VB program itself, then I've mostly used Ethernet with UDP, but also TCP where it is required by the device (rare). I've also used Serial with some devices. For UDP I've just the UDPClient class available in .Net and for Serial, the SerialPort component.

    Now, for the example, I made it pretty simple. I just increment a counter that counts from 0000 to 9999 and display the value on the form, using the bitmap images of the digits. I didn't create convenient classes, or subs to manage the digits display at a more abstract level as that would be more code and you sound like you would like to look at as little code as possible. No scaling, no tranforms or translates, just simple draw this bitmap at an x,y location on the form.

    I removed the border from the form, and set the bounds to 0, 0, 1024, 768 so it will display in the upper left corner of the monitor if you monitor is larger than that.
    I added code so you can double click on the form, or hit the escape key to close it.

    As mentioned, I have a bitmap in the resources with all 10 digits (in two rows), so the first task in the Load event handler is two loops to clone an area around each of the five digit in each row and create small bitmaps from them, assigned to an array so they can be access by digit number.

    The timer is started and it simply increments a counter, keeping it in the range 0 to 9999, and it invalidates the form.
    The invalidation causes the Paint Event to happen, and the paint event loops backward through each of the four digits of the counter and displays the digit on the form.
    It loops backwards as it is a little less code to isolate the digits one at a time going from least significant digit to the most significant.

    I didn't add a background image to the form. You can add an image to the BackgroundImage property in the Properties window of the IDE for the form, and see the digits being drawn on the background image.

    Here is what the code looks like, but I'll attach the project so you have the digits bitmap included in the project resource and can run that project (again using VS2010, but should load and run fine in the later versions).
    Code:
    Public Class Form1
    
      Private Counter As Integer
      Private DigitBmps(9) As Bitmap
    
      Private Sub Form1_KeyUp(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyUp
        If e.KeyCode = Keys.Escape Then Me.Close()
      End Sub
    
      Private Sub Form1_MouseDoubleClick(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDoubleClick
        Me.Close()
      End Sub
    
      Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
        Me.Bounds = New Rectangle(0, 0, 1024, 768)
        Dim rect As New Rectangle(8, 0, 32, 42)
    
        DoubleBuffered = True
    
        For i As Integer = 0 To 4
          DigitBmps(i) = My.Resources.SegmentedDigits.Clone(rect, Imaging.PixelFormat.Format32bppArgb)
          rect.X += 33
        Next
        rect.X = 8 : rect.Y = 43
        For i As Integer = 5 To 9
          DigitBmps(i) = My.Resources.SegmentedDigits.Clone(rect, Imaging.PixelFormat.Format32bppArgb)
          rect.X += 33
        Next
    
        Timer1.Interval = 100
        Timer1.Start()
      End Sub
    
      Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
        Counter += 1
        Counter = Counter Mod 10000  'only count 0 to 9999
        Invalidate()
      End Sub
    
      Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        Dim g As Graphics = e.Graphics
        Dim digit As Integer
        Dim digits As Integer = Counter
        Dim x As Integer = 300
        Dim y As Integer = 100
    
        For i As Integer = 3 To 0 Step -1
          digit = digits Mod 10
          digits = digits \ 10
          g.DrawImage(DigitBmps(digit), x, y)
          x = x - 32
        Next
      End Sub
    End Class
    p.s. To see a few more readouts in action, I modified the paint to do a nested loop, row and column, to do 5 columns by 11 rows of the readouts. After you've played around with the original project, perhaps you want to see how it runs when it is drawing 220 digit images 10 times per second on the form.

    Code:
      Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        Dim g As Graphics = e.Graphics
        Dim digit As Integer
        Dim digits As Integer = Counter
        Dim x As Integer = 300
        Dim y As Integer = 100
        For row = 100 To 600 Step 50
          For col As Integer = 200 To 1000 Step 180
            x = col : y = row
            digits = (Counter + row + col) Mod 10000
            For i As Integer = 3 To 0 Step -1
              digit = digits Mod 10
              digits = digits \ 10
              g.DrawImage(DigitBmps(digit), x, y)
              x = x - 32
            Next
          Next
        Next
    
      End Sub
    Also, since I have a large screen and I would like to move the example form around, I used this code to allow me to drag the form out of the upper left corner.
    Code:
      Private Sub Form1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
        Static lpos As Point
        If e.Button = Windows.Forms.MouseButtons.Left Then
          Me.Location += New Size(e.X - lpos.X, e.Y - lpos.Y)
        Else
          lpos = e.Location
        End If
      End Sub
    Attached Files Attached Files
    Last edited by passel; Jun 26th, 2020 at 07:23 PM.
    "Anyone can do any amount of work, provided it isn't the work he is supposed to be doing at that moment" Robert Benchley, 1930

  17. #17

    Thread Starter
    Lively Member
    Join Date
    Aug 2019
    Posts
    119

    Re: Using Windows 10, HDMI and monitors as an Embedded System

    Quote Originally Posted by passel View Post
    1. Ok. If you have different static bitmaps that you want to display, then you could just set the BackgroundImage of the form to that image, when you change it, rather than draw it. That will make the updating easier, i.e. you won't have to redraw the background in the paint event, and all the foreground dynamic parts will have been erased waiting for you to update them inside the Paint Event.

    You could also load each static bitmap in its own picturebox and have only the one that is currently active visible. Again, update all the dynamic portions in each paint event.

    2. Ok. In the example I'm posting, I loaded a single bitmap with the 10 digits in it, and when the example loads, I divided the single bitmap into 10 smaller single digit bitmaps. I did this to save me the time of having to create 10 single bitmaps in a paint program offline, but in the end uses multiple small bitmaps as you would.

    3. As mentioned in 1 (above), you have options. If you want to only draw the static image once, to avoid complications you would need to maintain a bitmap image in memory to work with, as your static buffer. But if would be easier to take advantage of the built in capability of the Picture or Form to maintain that static image by assigning the image to the Background Image of the Form, or the Image property of a picturebox. That way, whenever you invalidate the control, the Paint event is triggered and you have a fresh copy of the static image to draw on, without the previous things you've drawn on the background. You just draw all the dynamic stuff in the paint event and you're done.

    If you don't want to do it this way, and would rather maintain a static image in memory, and update it ad hoc, perhaps in parts without redoing all the dynamic stuff every pass, then that is another approach that can be done, but would take more explanation.

    4. Redrawing boolean already covered above. Not needed if you assign the image to the control.
    As for the dynamic image being a circle and showing the background through the circle, it depends on the image format. In order to see the background within the rectangle of the image, the image would have to contain transparent pixels, i.e. the pixels are defined by four values, alpha, red, green and blue values. if the alpha is 0, then the pixel will not be drawn so you would see the pixel "underneath". If the Alpha is 255 the color is opaque so you see the color from your image. Any value from 1 to 254, and you see a mixture of the pixel from the image and the pixel "underneath", 1 is almost all of the underneath pixel and 254 is almost all of the image pixels, and 128 would be an even mixture of the two.

    5. System.Drawing.Drawing2D is a standard .Net library so available in all the .Net versions.

    6. I'm sure there are many graphic libraries available. I have only used what is built into .Net, so accessible from VB and C# and other languages using the .Net Frameworks.

    7. If the Dynamic Data isn't being generated by the VB program itself, then I've mostly used Ethernet with UDP, but also TCP where it is required by the device (rare). I've also used Serial with some devices. For UDP I've just the UDPClient class available in .Net and for Serial, the SerialPort component.

    Now, for the example, I made it pretty simple. I just increment a counter that counts from 0000 to 9999 and display the value on the form, using the bitmap images of the digits. I didn't create convenient classes, or subs to manage the digits display at a more abstract level as that would be more code and you sound like you would like to look at as little code as possible. No scaling, no tranforms or translates, just simple draw this bitmap at an x,y location on the form.

    I removed the border from the form, and set the bounds to 0, 0, 1024, 768 so it will display in the upper left corner of the monitor if you monitor is larger than that.
    I added code so you can double click on the form, or hit the escape key to close it.

    As mentioned, I have a bitmap in the resources with all 10 digits (in two rows), so the first task in the Load event handler is two loops to clone an area around each of the five digit in each row and create small bitmaps from them, assigned to an array so they can be access by digit number.

    The timer is started and it simply increments a counter, keeping it in the range 0 to 9999, and it invalidates the form.
    The invalidation causes the Paint Event to happen, and the paint event loops backward through each of the four digits of the counter and displays the digit on the form.
    It loops backwards as it is a little less code to isolate the digits one at a time going from least significant digit to the most significant.

    I didn't add a background image to the form. You can add an image to the BackgroundImage property in the Properties window of the IDE for the form, and see the digits being drawn on the background image.

    Here is what the code looks like, but I'll attach the project so you have the digits bitmap included in the project resource and can run that project (again using VS2010, but should load and run fine in the later versions).
    Code:
    Public Class Form1
    
      Private Counter As Integer
      Private DigitBmps(9) As Bitmap
    
      Private Sub Form1_KeyUp(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyUp
        If e.KeyCode = Keys.Escape Then Me.Close()
      End Sub
    
      Private Sub Form1_MouseDoubleClick(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDoubleClick
        Me.Close()
      End Sub
    
      Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
        Me.Bounds = New Rectangle(0, 0, 1024, 768)
        Dim rect As New Rectangle(8, 0, 32, 42)
    
        DoubleBuffered = True
    
        For i As Integer = 0 To 4
          DigitBmps(i) = My.Resources.SegmentedDigits.Clone(rect, Imaging.PixelFormat.Format32bppArgb)
          rect.X += 33
        Next
        rect.X = 8 : rect.Y = 43
        For i As Integer = 5 To 9
          DigitBmps(i) = My.Resources.SegmentedDigits.Clone(rect, Imaging.PixelFormat.Format32bppArgb)
          rect.X += 33
        Next
    
        Timer1.Interval = 100
        Timer1.Start()
      End Sub
    
      Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
        Counter += 1
        Counter = Counter Mod 10000  'only count 0 to 9999
        Invalidate()
      End Sub
    
      Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        Dim g As Graphics = e.Graphics
        Dim digit As Integer
        Dim digits As Integer = Counter
        Dim x As Integer = 300
        Dim y As Integer = 100
    
        For i As Integer = 3 To 0 Step -1
          digit = digits Mod 10
          digits = digits \ 10
          g.DrawImage(DigitBmps(digit), x, y)
          x = x - 32
        Next
      End Sub
    End Class
    p.s. To see a few more readouts in action, I modified the paint to do a nested loop, row and column, to do 5 columns by 11 rows of the readouts. After you've played around with the original project, perhaps you want to see how it runs when it is drawing 220 digit images 10 times per second on the form.

    Code:
      Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        Dim g As Graphics = e.Graphics
        Dim digit As Integer
        Dim digits As Integer = Counter
        Dim x As Integer = 300
        Dim y As Integer = 100
        For row = 100 To 600 Step 50
          For col As Integer = 200 To 1000 Step 180
            x = col : y = row
            digits = (Counter + row + col) Mod 10000
            For i As Integer = 3 To 0 Step -1
              digit = digits Mod 10
              digits = digits \ 10
              g.DrawImage(DigitBmps(digit), x, y)
              x = x - 32
            Next
          Next
        Next
    
      End Sub
    Also, since I have a large screen and I would like to move the example form around, I used this code to allow me to drag the form out of the upper left corner.
    Code:
      Private Sub Form1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
        Static lpos As Point
        If e.Button = Windows.Forms.MouseButtons.Left Then
          Me.Location += New Size(e.X - lpos.X, e.Y - lpos.Y)
        Else
          lpos = e.Location
        End If
      End Sub
    Thank you so much for such effort in your reply. I did not expect such a great explanation, but most welcome. This should be enough for me to make considerable progress. I will keep you updated, if this is OK, and thank you for such a great start.

  18. #18

    Thread Starter
    Lively Member
    Join Date
    Aug 2019
    Posts
    119

    Re: [RESOLVED] Using Windows 10, HDMI and monitors as an Embedded System

    Perfect solution...thank you so much BasicBasic is getting better thanks to everybody on this outstanding site.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width