Umgang mit Graphics unklar : Erstellung u Uebergabe an Funktion

wolf_703

Aktives Mitglied
moin,
im Rahmen meines Spielprojektes "Boeing Cockpit Flugsimulator" werden ein PC/Laptop/miniPC und
ein Arduino nano fuer das Steuer verwendet.
Dafuer benoetige ich im Wesentlichen einen künstlichen Horizont und einen Radarkompass.
Im Original sieht der künstliche Horizont so aus :
Cockpit_Boeing787-9_img1.jpg

was ich hier evtl so darstellen könnte :
screenshot_polygon4artific_horizon2_reduced.jpg

der Horizont ist natuerlich beweglich, gesteuert durch Datenuebernahme von einem Arduino Nano,
der die Stellung von Potentiometern abliest und als Datenstrings uebermittelt. Zur Programmierung in Java wurde
aber erstmal eine Simulationsfunktion simulate_horizon_gliding(Graphics g) angelegt.

Insgesamt gibt es 6 nebeneinanderliegende Panels mit
Geschwindigkeit, kuenstl.Horizont,Flughoehe,Radarkompass, Zeitanzeige, Maschinenparameter
sowie ein darueberliegendes breites Panel mit ILS-Daten und Autopilotdaten usw,
und ein darunterliegendes breites Panel fuer checklists, Taxiway-Daten usw.

Zur weiteren Info bitte mal die zahlreichen Youtube-Filme (cabrides) anschauen, die gute Sichen
auf die Cockpit-Betandteile nebst zahlreichen Erklaerungen anbieten..

Da ich zwischendurch jetzt mal kurz raus muss, gehts im naechsten Beitrag weiter, sorry !
 
moin,
so jetzt gehts weiter !
Habe erstmal ein paar Dateien zum Mitlesen anzubieten:
Fsim_panels1 exportiertes Netbeans-8.1-Projekt in Zip : laesst sich hier Nicht beifuegen !?
Fsim_panels1.java
PolygonGenerator.java
jSerialComm-2.11.0.jar

hier der Code , um den es geht :
Java:
package fsim_panels1;

import java.awt.*;
import javax.swing.*;
import javax.swing.border.TitledBorder;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.concurrent.TimeUnit;

import com.fazecast.jSerialComm.*;

public class Fsim_Panels1 extends JFrame{

    /**
     * @param args the command line arguments
     */
    public static JPanel ptop  = null;    //-Panel fuer diverse Einstellungen (Flughoehe,Std.Geschwindigkeit usw
    
    public static JPanel phv = null;    //-Panel fuer Geschwindigkeitsanzeige
    public static JPanel phh = null;    //-Panel fuer Horizontanzeige
    public static JPanel pha = null;    //-Panel fuer Hoehenanzeige
    public static JPanel pk = null;     //-Panel fuer Kompassanzeige
    public static JPanel pm = null;     //-Panel fuer Maschinenanzeige
    public static JPanel pt = null;             //-Panel fuer Zeitanzeige
    
    public static JPanel pbottom  = null;       //-Panel fuer diverse Einstellungen (Flughoehe,Std.Geschwindigkeit usw   
    public static PolygonGenerator pg = null;   //- erzeugt Hintergrund und Trapez fuer den Vordergrund
    public static int y_high_parts = 0;         //- die hohen Panes fuer Horizont usw
    public static int h_high_parts = 490;       //- dito
    public static int y_startline_high_parts = 35;  //- dito
    
    public static void main(String[] args) {
        JFrame fMain_frame = new JFrame("Main-Panel");
        fMain_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        fMain_frame.setBounds(100, 100, 1000, 600);
        fMain_frame.setTitle("Boeing-Cockpit");
        fMain_frame.setBackground(Color.yellow);
        //fMain_frame.setLayout(new GridLayout(1,6));
        fMain_frame.setLayout(new BorderLayout());
        
        panel_top();
        fMain_frame.getContentPane().add(ptop,BorderLayout.NORTH);
        
        panel_velocity();
        fMain_frame.getContentPane().add(phv);
        panel_artific_horizon();
        fMain_frame.getContentPane().add(phh);
        panel_altitude();
        fMain_frame.getContentPane().add(pha);       
        panel_kompass();
        fMain_frame.getContentPane().add(pk); 
        panel_machine();
        fMain_frame.getContentPane().add(pm);         
        panel_time();
        fMain_frame.getContentPane().add(pt);         

        panel_bottom();
        fMain_frame.getContentPane().add(pbottom,BorderLayout.SOUTH);
        
        fMain_frame.revalidate();       
        fMain_frame.setVisible(true);
        simulate_horizon_gliding(Graphics g);
    }
        public static void panel_top() {
            ptop = new JPanel();
            ptop.setBackground(Color.PINK);
            ptop.setBounds(0, 0, 0, 50);
            ptop.setLayout(new BorderLayout());
            JLabel lblFirst = new JLabel("several items"); 
            lblFirst.setHorizontalTextPosition(JLabel.CENTER);
            lblFirst.setVerticalTextPosition(JLabel.TOP);
            lblFirst.setBorder(new TitledBorder("panel_top"));
            ptop.add(lblFirst);
            ptop.revalidate();
            ptop.setVisible(true);
    }   

    public static void panel_velocity() {
            phv = new JPanel();
            phv.setBackground(Color.red);
            phv.setBounds(0, y_startline_high_parts+y_high_parts, 100, h_high_parts);
            phv.setPreferredSize(new Dimension(100, h_high_parts));
            phv.setLayout(new BorderLayout());
            JLabel lblFirst = new JLabel("kt/h"); 
            lblFirst.setHorizontalTextPosition(JLabel.CENTER);
            lblFirst.setVerticalTextPosition(JLabel.TOP);
            lblFirst.setBorder(new TitledBorder("panel_velocity"));
            phv.add(lblFirst);
            phv.revalidate();
            phv.setVisible(true);
    }
    
    public static void panel_artific_horizon() {
            phh = new JPanel();
            phh.setBackground(Color.BLACK);
            phh.setBounds(100, y_startline_high_parts+y_high_parts, 300, h_high_parts);
            phh.setPreferredSize(new Dimension(300, h_high_parts));
            phh.setLayout(new BorderLayout());
            /*
            JLabel lblFirst = new JLabel("alt.position"); 
            lblFirst.setHorizontalTextPosition(JLabel.CENTER);
            lblFirst.setVerticalTextPosition(JLabel.TOP);
            lblFirst.setBorder(new TitledBorder("panel_horizon"));
            phh.add(lblFirst);
            */
            PolygonGenerator pg = new PolygonGenerator();
            phh.add(pg);
            phh.revalidate();
            phh.setVisible(true);
    }
    
    public static void panel_altitude() {
            pha = new JPanel();
            pha.setBackground(Color.BLUE);
            pha.setBounds(400, y_startline_high_parts+y_high_parts, 100, h_high_parts);
            pha.setPreferredSize(new Dimension(100, h_high_parts));
            pha.setLayout(new BorderLayout());
            JLabel lblFirst = new JLabel("feet"); 
            lblFirst.setHorizontalTextPosition(JLabel.CENTER);
            lblFirst.setVerticalTextPosition(JLabel.TOP);
            lblFirst.setBorder(new TitledBorder("altitude"));
            pha.add(lblFirst);
            pha.revalidate();
            pha.setVisible(true);
    }
    
    public static void panel_kompass() {
            pk = new JPanel();
            pk.setBackground(Color.CYAN);
            pk.setBounds(500, y_startline_high_parts+y_high_parts, 300, h_high_parts);
            pk.setPreferredSize(new Dimension(300, h_high_parts));
            pk.setLayout(new BorderLayout());
            JLabel lblFirst = new JLabel("direction"); 
            lblFirst.setHorizontalTextPosition(JLabel.CENTER);
            lblFirst.setVerticalTextPosition(JLabel.TOP);
            lblFirst.setBorder(new TitledBorder("panel_kompass"));
            pk.add(lblFirst);
            pk.revalidate();
            pk.setVisible(true);
    }

    public static void panel_machine() {
            pm = new JPanel();
            pm.setBackground(Color.ORANGE);
            pm.setBounds(800, y_startline_high_parts+y_high_parts, 100, h_high_parts);
            pm.setPreferredSize(new Dimension(100, h_high_parts));
            pm.setLayout(new BorderLayout());
            JLabel lblFirst = new JLabel("machine"); 
            lblFirst.setHorizontalTextPosition(JLabel.CENTER);
            lblFirst.setVerticalTextPosition(JLabel.TOP);
            lblFirst.setBorder(new TitledBorder("panel_machine"));
            pm.add(lblFirst);
            pm.revalidate();
            pm.setVisible(true);
    }
    public static void panel_time() {
            pt = new JPanel();
            pt.setBackground(Color.GREEN);
            pt.setBounds(900, y_startline_high_parts+y_high_parts, 100, h_high_parts);
            pt.setPreferredSize(new Dimension(100, h_high_parts));
            pt.setLayout(new BorderLayout());
            JLabel lblFirst = new JLabel("flyer-time"); 
            lblFirst.setHorizontalTextPosition(JLabel.CENTER);
            lblFirst.setVerticalTextPosition(JLabel.TOP);
            lblFirst.setBorder(new TitledBorder("panel_time"));
            pt.add(lblFirst,BorderLayout.EAST);
            pt.revalidate();
            pt.setVisible(true);
    }
    
    public static void panel_bottom() {
            pbottom = new JPanel();
            pbottom.setBackground(Color.MAGENTA);
            pbottom.setBounds(0, 0, 0, 50);
            pbottom.setLayout(new BorderLayout());
            JLabel lblFirst = new JLabel("several items"); 
            lblFirst.setHorizontalTextPosition(JLabel.CENTER);
            lblFirst.setVerticalTextPosition(JLabel.TOP);
            lblFirst.setBorder(new TitledBorder("panel_bottom"));
            pbottom.add(lblFirst);
            pbottom.revalidate();
            pbottom.setVisible(true);
    }   
    
    public static void simulate_horizon_gliding(Graphics g){
        Color c_brown = new Color(128,128,110);
        Color c_blue_light = new Color(176,224,250);
        int y_baseline = 5;
        int win_width = 400;
        int numberofpoints = 4;         
        int border_point_left = 5;
        
        int[] border_points_y = {0,60,80};
        // x coordinates of vertices
        int x[] = { border_point_left, border_point_left, win_width, win_width};
        int y[] = { border_points_y[0]+y_baseline, border_points_y[1]+y_baseline, border_points_y[2]+y_baseline, border_points_y[0]+y_baseline };         
        int i = 0;
        for(i=0;i < 10;i++)
        {
            y[1] = border_points_y[1]+y_baseline+i;
            y[2] = border_points_y[2]+y_baseline-i;
            pg.neu_zeichnen(g,5,400,c_brown,4,x,y);
            try{
                TimeUnit.SECONDS.sleep(1000);
        }catch(InterruptedException e){}                 
        }
        
    }

Problem ist die Zeile :
Code:
public static void simulate_horizon_gliding(Graphics g){
hab schon einiges probiert, aber kriege Nicht die Uebergabe von Graphics hin..
evtl hab ich "Tomaten auf den Augen"😄
Netscape schlaegt vor
Code:
import java.awt.Graphics.*;
hilft garnix..

wer wer weiss Rad ?
 

Anhänge

Hab mal was probiert:
Java:
public static void simulate_horizon_gliding(){
       
        pg = new PolygonGenerator(); //- <<-- wird das Objekt Nicht erzeugt ?
        Graphics g = pg.getGraphics();
        Color c_brown = new Color(128,128,110);
        Color c_blue_light = new Color(176,224,250);
        int y_baseline = 5;
        int win_width = 400;
        int numberofpoints = 4;        
        int border_point_left = 5;
       
        int[] border_points_y = {0,60,80};
        // x coordinates of vertices
        int x[] = { border_point_left, border_point_left, win_width, win_width};
        int y[] = { border_points_y[0]+y_baseline, border_points_y[1]+y_baseline, border_points_y[2]+y_baseline, border_points_y[0]+y_baseline };        
        int i = 0;
        for(i=0;i < 10;i++)
        {
            y[1] = border_points_y[1]+y_baseline+i;
            y[2] = border_points_y[2]+y_baseline-i;
            pg.neu_zeichnen(g,5,400,c_brown,4,x,y); //<<-- hier NullpointerException !?
            try{
                TimeUnit.SECONDS.sleep(1000);
        }catch(InterruptedException e){}                
        }
       
    }

verstehe nur noch Bahnhof !
 
Also diesen Ansatz ist aus meiner Sicht unüblich. Wenn ich ein Spiel in Swing geschrieben habe, war mein Ansatz immer folgender:

  • Ich habe in der Spiel-Schleife immer ein BufferedImage erzeugt. Dieses wurde dann dem UI Thread bereit gestellt und der UI Thread wurde informiert (ein einfaches repaint() auf einem Control z.B.)
  • Der UI Thread hat in der paint bzw. im paintComponent dann immer nur geschaut: Gibt es ein neues Image? Wenn ja, wurde das alte Image wieder in einer Art Pool bereit gestellt und das neue Bild wurde als aktuelles Bild genommen. Anschließend wurde das Bild gemalt.

Dieses direkt auf einem Canvas malen kommt mit dem Problem, dass Du bei Aktualisierungen eben genau diese nicht mehr hast. Also wenn Du das Fenster klein machst und wieder öffnest, dann malt sich das alles nur mit paint / paintComponent und alles, was Du direkt gemalt hast ist weg.

Das kann aber natürlich eine Idee sein, wenn Du nur etwas hinzufügen willst. Also eine Linie wird hinzu gefügt (einfach mal als Beispiel):
  • Du malst diese direkt auf dem Control / Canvas.
  • Für ein späteres paint/paintComponent mekrst Du Dir die Linie
  • Es wird kein komplettes repaint() ausgelöst. Du sparst also etwas.

Bei Dir willst Du aber nicht nur etwas hinzu fügen - Du veränderst ja z.B. dein künstlichen Horizont. Damit musst Du den Bereich komplett neu malen. (Was übrigens einfach gehen kann. Du hast ein großes Bild und Du musst das Bild "nur" drehen und einen Ausschnitt malen. Hat Graphics2D nicht entsprechende Methoden? Habe ich zu lange nicht mehr genutzt).

Was man probieren kann ist evtl. ein erzeugen von einzelnen Grafiken für die einzelnen Kontrollen und die Sicht und so um das dann direkt zu malen. Aber ich meine, das das zu einem Flackern oder so führen kann. Aber das wäre noch eine Idee um das repaint() zu verhindern.
 
hallo KonradN,

danke für Interesse und Tipps.
Im Ruhefall sind blaue und braune Fläche gleich hoch.
Es passieren folgende Änderungen dynamisch :
1.)
Das "Steuerrad" wird nach links oder rechts gedreht, entsprechend kippt der künstliche Horizont
bzw das hellblaue Trapez entgegengesetzt, an der darunterliegenden braunen Fläche ändert sich nix,
sie wird von der blauen überdeckt !
Die Linien müssen dann neu gezeichnet werden.
Im Originalcockpit befinden sich auf gleichem Bildschirm links die Geschnwindigkeits- und rechts die
recht komplexe Höhenanzeige; diese kommen bei mir auf ein extra Panel,ist wohl erstmal einfacher.

2.) Wird das "Steuerrad" zum Körper gezogen(nach hinten) , geht die Flugzeugnase nach oben - takeoff.
Dann wird die blaue Fläche größer.
Bei der Landung wird die braune Fläche größer, die "Nase" geht also nach unten.

Es ist durchaus möglich oder sogar wahrscheinlich, daß die Fälle 1) und 2) gleichzeitig auftreten.

Die Stellung des "Steuerrades" wird über Potentiometer einem Arduino vermittelt,der
wiederum über die COM-Schnittstelle seriell dieser Anwendung die Infos zu 1) und 2) mitteilt;
es muß also laufend gelesen und gemalt werden...

Daß es bei den großen Flyern - ob Airbus oder Boeing - noch eine dritte Steurung und Stellung
für das Bugrad gibt, soll hier erstmal unbetrachtet bleiben..

Evtl ist mein ganzer Code-Ansatz verkehrt..hab ja als Rentner Zeit oder net ?🙄
 
hab schon einiges probiert, aber kriege Nicht die Uebergabe von Graphics hin..
Du willst so wie es ausschaut direkt auf deinen JFrame zeichnen. Dazu musst du schon die Paint Methode von deinen JFrame überschreiben.
Denn nur da kommst du an das Graphics was du für deine Zeichen Methode brachst.
Mit deinen PolPolygonGenerator der von Caves erbt kommst du nicht an das Graphics was du brauchst.

Der Aufruf in der Main Methode ist falsch.
simulate_horizon_gliding(Graphics g);
Einfach „Graphics g“ ist zwar vielleicht für den Compiler Ok aber logisch falsch.

Nochmal du brauchst das Graphics vom geerbten JFrame .


Auch finde ich es nicht sinnvoll einfach den UI Thread eine sek anzuhalten in der Methode simulate_horizon_gliding.

 
Zuletzt bearbeitet:
Java:
 pg.neu_zeichnen(g,5,400,c_brown,4,x,y); //<<-- hier NullpointerException !?
Hier willst du die Methode neu zeichnen aufrufen aber welchen Graphics übergibst du hier?
Welchen brauchst du oder welchen hast du schon in der Klasse Polygon...?
Dann Merke in dir in der Klasse in einer Instanzvariable.

Keiner Tipp
wenn du eine Methode Überscheschreibst solltest du das @Override benutzen.

mit getGraphics() bekommst du das Graphics vom JFrame.

 
Zuletzt bearbeitet:
habe es mal etwas verändert so das zumindest deine Animation läuft

sehr wichtig hier auch
public static void panel_artific_horizon() {
phh = new JPanel();

keine neue Lokale Variabe erstellen
 

Anhänge

Zuletzt bearbeitet:
moin,

alles etwas umgestellt , gings schon besser :
im jeweiligen Frame gibt es Keinen Graphics-Kontext mehr,
wird jetzt alles in frame-spezischer Klasse gemacht,
auch das Lesen der Steuerelemente.

ToDo :
Aber es gibt ein Array zur Uebergabe von Werten zwischen den Frames für Horizont und Kompass.
Dieser muß den Aenderungen durch Kurvenflug (p_azimute) folgen und bildet die Fluglinie für einen
begrenzten Zeitabschnitt ab.


beigefuegt die beiden Quelldateien..
 

Anhänge

moin,

also, der bisherige Ansatz wird komplett verworfen !

es erscheint mir günstiger, lediglich einen Frame mit einem einzigen Graphics für alle Instrumente
zu verwalten ; Aufteilung durch Rechtecke usw. und man kann ja auch im Grafik-Kontext Texte darstellen.

Auf ein Neues.pictures and .code comes soon !
 
Hallo
Du wirst dich bei diesen Projekt doch etwas mit Threads Nebenläufigkeit beschäftigen müssen.
Denn bei der Abfrage der Seriellen Schnittstelle hältst du den Thread an. Bist in einer Endlos Schleife.
 
moin,
Java:
Threads Nebenläufigkeit
ja das wird auch noch bearbeitet werden müssen..

Erstmal habe ich alle Instrumente auf einen einzigen Grafik-Kontext gesetzt und der Horizont
funzt soweit erstmal..

Für den Kompass brauche ich konzentrische Kreise mit einem Radius größer als die vorgesehene
Kompass-Panelbreite.Da muß wohl Clipping eingesetzt werden, damit Kreise Nicht andere Panels übermalen
..habe ich noch nie gemacht.

Bisher finde ich Keine Bespiele, wo nicht irgendwelche Bilder beschnitten, sondern geometrische Objekte gezeichnet werden..
Oder ich erzeuge ein passendes Bild, aber wie mache ich dann die Dynamische Teilung auf dem äußersten Kreis ?
Die muß sich ja beim Ändern der Flugrichtung verschieben !

Ein schönes Winterprojekt, gelle ?
 
links der künstliche Horizont, rechtsoben der Kompass und
rechtsunten der Winkel vom Bugrad - engl. nosewheel (hihi)

Hier ist ja alles Simulation, weil Euch ja nicht die reale Mechanik und Elektronik
in Form von Potentiometern und dem Arduino an USB für Azimute(Flugrichtung),Elevation(Neigung bzw Sinken oder Steigen)
sowie die Stellung des Bugrades (Rollen auf dem Taxiway) zur Ver Verfügung steht.

ToDo :
Geometrie beim Bugrad prüfen
in "reserve" Maschinenstatus (Triebwerk), Uhrzeit..

so, jetzt dürft Ihr schimpfen🙄
 
Zuletzt bearbeitet:
Was ich auch nicht sinnvoll finde eigentlich falsch ist, das du mitten in der paint() Methode dein
Ablauf Zyklus startest. „produce_horizon(Graphics g)“
Du verlässt somit die paint() Methode nie. Das ist für eine GUI nicht gut meist auch tödlich.

Genau das würdest du auch machen wenn du mit deiner RS232 arbeitest.
Dann ist das sogar eine Endlosschleife.

Tipp entweder du machst die Start Methode nicht Privat kannst die somit von der Main aus satten.
Oder benutze einen Konstruktor und starte dort.

Kannst dann auch ein Repaint() ausführen.
 
Hier mal ein Screenshot, wenn man deinen Code in VSCode öffnet:
1729929943413.png
Alles völlig bunt und voller Warnungen, quasi in jeder Zeile. Das ist nur VSCode, IntelliJ würde sich vermutlich in ein Schwert stürzen. Der Compiler schafft das schon. Dennoch allein die Anzahl der Klassenvariablen macht den Code unwartbar.
 

Zurück
Oben