C# Bildschirmausschnitt in PictureBox "Streamen"



  • Hallo erstmal. Ich habe ein kleines Problem.
    Ich habe es geschaft einen bestimten Bildschirmausschnitt in ein zweites Fenster zu packen bloß zwei Dinge kriege ich nicht hin.

    1. Ich möchte, dass das Bild immer auf die größe des Fenster angepasst wird, also so groß gemacht wird bis es, entweder den oberen oder den seitlichen Rand, erreicht.
    2. Möchte ich, dass das Bild 10 mal in der Sekunden erneuert wird, damit ich kein Standbild habe und die Änderungen zeitnah übernommen werden. (Es muss kein flüssiges Video ergeben).
     namespace Kasse
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
    
                DisplayImage();
            }
    
          
    
            private void DisplayImage()
            {
                
                
                //Mach das Foto des Bildschirms.
                Rectangle rect = new Rectangle(0, 0, 600, 600);
                Bitmap bmp = new Bitmap(rect.Width, rect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                Graphics g = Graphics.FromImage(bmp);
                g.CopyFromScreen(rect.Left, rect.Top, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);
    
                //Erstellt eine neue PictureBox im Fenster.
                PictureBox imageControl = new PictureBox();
                imageControl.Width = 600;
                imageControl.Height = 600;
    
                imageControl.Dock = DockStyle.Fill;
                imageControl.Image = (Image)bmp;
                imageControl.SizeMode = PictureBoxSizeMode.CenterImage;
                Controls.Add(imageControl);
            
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                
            }
    
    
        }
    
    }
    

    Es wäre super wenn mir jemand helfen könnte. Stehe total auf dem Schlauch.

    Schonmal Danke für die Hilfe.



  • Zu 1.: Möchtest du das Bild dann im Fenster zoomen? Dann benutze PictureBoxSizeMode.Zoom.
    Oder sollen die "600 x 600" variabel sein?

    Für 2.: Benutze einen Timer mit Interval = 100.
    Erstelle dann aber nur einmalig die PictureBox und Bitmap und führe im Timer.Tick-Ereignis nur noch das Kopieren aus (+ evtl. Invalidate() bzw. Update()).



  • Erstmal Danke für die schnelle Hilfe.

    1. Problem mit imageControl.SizeMode = PictureBoxSizeMode.Zoom; gelöst. Genau so wollte ich es haben.(Hätte ich auch selber drauf kommen können *Facepalm*)
    2. Das Bild akktualisiert sich jetzt zwar. Aber nur wenn ich das Fenster bewege oder die Größe ändere.
      Ich glaube das könnte daran liegen, dass ich Update(); und Invalidate(); noch nicht ganz verstehen bzw. an der falschen Stelle benutze?
    private void DisplayImage()
            {
                
                
                //Mach das Foto des Bildschirms.
                Rectangle rect = new Rectangle(0, 0, 600, 600);
                Bitmap bmp = new Bitmap(rect.Width, rect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                Graphics g = Graphics.FromImage(bmp);
                g.CopyFromScreen(rect.Left, rect.Top, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);
    
                //Erstellt eine neue PictureBox im Fenster.
                PictureBox imageControl = new PictureBox();
        
    
                imageControl.Dock = DockStyle.Fill;
                imageControl.Image = (Image)bmp;
                imageControl.SizeMode = PictureBoxSizeMode.Zoom;
                Controls.Add(imageControl);
    
                Timer t1 = new Timer(); 
                t1.Interval = 100; 
                t1.Tick += new EventHandler(t1_Tick); 
                t1.Start(); 
    
                void t1_Tick(object sender, EventArgs e)
                {
                    g.CopyFromScreen(rect.Left, rect.Top, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);
                    Update();
                    Invalidate();
                }
            }
    


  • Rufe es für die PictureBox auf, denn diese möchtest du ja aktualisieren lassen:

    imageControl.Invalidate(); // or Update();
    


  • Super danke. Alles gelöst.



  • Okay also ich habe noch eine Frage/Bitte.
    Ich möchte gerne den Bildauschnitt beim staten des programmes einmal per Maus auswählen (Wie z.B. im Snipping Tool) doch nach ein paar Tagen überlegen bin ich immernoch kein Stück weiter. Das einzigste gute Beispiel was ich finde ist in VB.Net und daraus werde ich auch nicht schlau:
    https://drive.google.com/uc?export=download&id=1ka6pLz5ekX1ngqz1KqOMBXCU1tjK9duj

    Kann mir jemand bitte mit einem Code Beispiel in C# helfen?

    Oder mir zeigen wie ich z.B. sowas wie oben in mein Programm einbinden könnte?



  • Dann schau dir z.B. Creating an Image Viewer in C# Part 5: Selecting Part of an Image oder Cropping Images an.
    Grundlage dafür sind die Maus-Ereignisse und das Paint-Ereignis zum Anzeigen des Selektionsrechtecks.

    PS: Bei meiner Komponente Paint# - eine Zeichenkomponente habe ich diese Funktionalität auch drin (aber keinen Source-Code dazu veröffentlicht), s.a. mein Beitrag in myCSharp.de - Komponente zur Bildbearbeitung.



  • Ich glaub, er will einen beliebigen Bildschirmbereich auswählen, nicht in seiner PictureBox. Das ist schon deutlich komplizierter.



  • OK, das macht natürlich mehr Sinn (bezogen auf die Ausgangsfrage).
    Das Snipping Tool verwendet dafür ein eigenes (leicht transparentes, rahmenloses) Vollbild-Fenster, auf dem dann die Selektion durchgeführt wird. Und dann passen wiederum die Lösungen in den obigen Links.



  • Das ist eine interessante Idee, da wäre ich zugegebenermaßen sponan nicht draufgekommen. Ich hätt über WinApi direkt auf dem Desktop gezeichnet.



  • Mechanics hat Recht. Ich möchte einen belibiegen Bildschirmbereich auswählen.
    Das versuche ich grade indem ich einmal ein Foto des gesamten bildschirms machen dan in der nun angezeigten PictureBox einen Bereich auswähle: Cropping Images und nachdem man den Button gedrückt hat, die Picture Box mit einem neuen (immer akktualisierendem) Bild des ausgewählten Bereiches anzeigen lasse. Doch hier ein Paar Probleme:

    1. Das asuwählen der Bilder fuktioniert bei mir nicht. Weder bei mir im Code noch bei dem Beispiel. Beim Beispiel sagt es "Mir Zu wenig Arbeitspeicher"? Und in meinem eigenen Code reagiert es garnicht auf meine maus.
    2. Unabhängig von dem "Cropping Code" passiert bei mir nichts wenn ich auf den Button Drück: Das neue Bild wird nicht angezeigt.
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    
    namespace Kasse
    {
        public partial class Form1 : Form
        {
            private bool _button1;
            private bool _selecting;
            private Rectangle rect;
    
            public Form1()
            {
                InitializeComponent();
    
                Selection();
    
                DisplayImage();
            }
    
            private void Selection()
            {
                //Mach das Foto des Bildschirms.
                Rectangle rect2 = new Rectangle(0, 0, 1440, 900);
                Bitmap bmp = new Bitmap(rect2.Width, rect2.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                Graphics g = Graphics.FromImage(bmp);
                g.CopyFromScreen(rect2.Left, rect2.Top, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);
    
                pictureBox1.Dock = DockStyle.Fill;
                pictureBox1.Image = (Image)bmp;
                pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
                Controls.Add(pictureBox1);
    
                button1.Dock = DockStyle.Bottom;
    
    
    
            }
            private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
            {
                // Starting point of the selection:
                if (e.Button == MouseButtons.Left)
                {
                    _selecting = true;
                    rect = new Rectangle(new Point(e.X, e.Y), new Size());
                }
            }
    
            private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
            {
                // Update the actual size of the selection:
                if (_selecting)
                {
                    rect.Width = e.X - rect.X;
                    rect.Height = e.Y - rect.Y;
    
                    // Redraw the picturebox:
                    pictureBox1.Refresh();
                }
            }
    
            private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
            {
                if (e.Button == MouseButtons.Left && _selecting)
                {
    
                    _selecting = false;
                }
            }
    
            private void pictureBox1_Paint(object sender, PaintEventArgs e)
            {
                if (_selecting)
                {
                    // Draw a rectangle displaying the current selection
                    Pen pen = Pens.GreenYellow;
                    e.Graphics.DrawRectangle(pen, rect);
                }
            }
    
    
            private void DisplayImage()
            {
                while (_button1)
                {
                    Rectangle rect = new Rectangle(200, 200, 440, 90);
                    Bitmap bmp = new Bitmap(rect.Width, rect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                    Graphics g = Graphics.FromImage(bmp);
                    g.CopyFromScreen(rect.Left, rect.Top, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);
    
                    pictureBox1.Dock = DockStyle.Fill;
                    pictureBox1.Image = (Image)bmp;
                    pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
                    Controls.Add(pictureBox1);
    
                    //Erstellt den Ticker
                    Timer t1 = new Timer();
                    t1.Interval = 40;
                    t1.Tick += new EventHandler(t1_Tick);
                    t1.Start();
    
                    void t1_Tick(object sender, EventArgs e)
                    {
                        //Macht das Foto erneut und aktualisiert die Picturebox
                        g.CopyFromScreen(rect.Left, rect.Top, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);
    
                        pictureBox1.Invalidate();
                    }
                }
            }
    
                private void Form1_Load(object sender, EventArgs e)
                {
                
                }
    
    
            private void button1_Click(object sender, System.EventArgs e)
            {
                _button1 = true;
            }
        }
            
    }
    
    

    Ich muss mir den Artikel von Th69 noch genauer durchlesen, so das ich 1. vieleicht selber lösen kann.
    Aber bei 2. habe ich keine Ahnung.



  • Was soll denn die Schleife

    while (_button1)
    {
        // ...
    }
    

    ?
    Lies mal [FAQ] Warum blockiert mein GUI?