Turniersoftware Anzeige

Fragen zu Tkinter.
Antworten
GhostFace
User
Beiträge: 2
Registriert: Freitag 22. August 2025, 19:39

Hallo liebe Community,
da ich relativ neu in der Programmierwelt bin stoße ich öfters mal auf Probleme
und komme bei diesem leider nicht weiter.
Und zwar arbeite ich aktuell an einer Software (Anbei 2 Bilder wie es eigentlich aussehen sollte)
für die Turnierverwaltung. Bei uns laufen immer 2 Spiele auf einem Feld und das im Wechsel. Also z.B.
Team A v Team B und Team C v Team D. Das Interface zeigt immer das Aktive Spiel in der Mitte in Rot an
und verschiebt das Inaktive Spiel nach oben oder unten, je nachdem ob es das Spiel 1 oder 2 ist. Genauso
verhält es sich mit der Spielzeit in der Mitte. Nach jedem Punkt werden die Seiten gewechselt und die Team
Namen und die dazugeh. Daten in der Seite verschoben. Die Funktionen und Darstellungen funktionieren an
meinem PC Problemlos.
Nun jedoch zu meinem Problem. Nachdem ich das Programm nun in unserer Halle Testen wollte
und das ganze nun auf meinem Laptop und mittels Beamer auf einer Leinwand habe anzeigen
lassen ist mir aufgefallen, dass sich das komplette Layout der GUI verschoben hat und die
Elemente dort teilweise ineinander sind. Durch Googeln ist es mir dann aufgefallen, dass
es mit großer Wahrscheinlichkeit daran liegt, dass ich die Positionierung der Elemente mittels
Place erledigt habe. Ich habe es nun mehrmals nachträglich versucht anders zu lösen und aufzubauen,
so dass es auch auf verschiedenen Bildschirmen immer gleich aussieht und nicht teilweise so ist,
dass Elemente abgeschnitten/ ineinander sind etc. habe es jedoch überhaupt nicht geschafft,
ansatzweise ein ähnliches Resultat zu erzielen.

Habt ihr irgendwelche Tipps, wie ich an die Sache herangehen kann, so dass das Layout sich vom Aussehen
her nicht großartig ändert wenn sich die Größe des Fensters/Bildschirms ändert?
Auch wäre interessant, was sich hier besser eignen würde, Pack oder Grid? Oder Kann/ sollte ich hier die
Beiden kombinieren und die Team Felder mittels Pack erstellen und diese dann mittels Grid auf der GUI Platzieren?


Ich bin so langsam komplett am verzweifeln und bräuchte dringend ein paar Tipps, auch wenn sich vermutlich
einige gerade die Augen im Kopf verdrehen, weil ich mit so Grundlegendem schon so massive Probleme habe
und es vermutlich eigentlich ein Kinderspiel wäre.

Bild

Bild
juwido
User
Beiträge: 26
Registriert: Donnerstag 15. Dezember 2022, 13:41

Also am einfachsten ist Pack, aber das macht halt manchmal nicht das, was man möchte. Grit bietet deutlich mehr Eingriffsmöglichkeiten. Zusätzlich kann man z.B. Elemente auf Frames anordnen und die dann wiederum platzieren. Direkt mischen kann man Pack und Grit nicht, sondern auf einer Ebene immer nur einheitlich.
Sirius3
User
Beiträge: 18290
Registriert: Sonntag 21. Oktober 2012, 17:20

@GhostFace: Du mußt die logische Struktur in Deinem Layout abbilden.
Also so wie das Fenster aussieht, hast Du ein 5x3-Grid. Und darin dann Frames, die wiederum Elemente enthalten, die aussehen, als ob man sie per pack übereinander packen kann.

Ansonsten vermeidet man diese etwas antiquierte Darstellung, in dem man einen lokalen HTTP-Server startet, und die Darstellung einem Browser in Vollbildmodus erledigen läßt. Dort hat man die gesamte Flexibilität, die einem CSS so bietet.

Chat-GPT liefert zum Beispiel für Deine Bilder so etwas:

Code: Alles auswählen

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Scoreboard</title>
  <style>
    :root{
      --bg:#f3f3f3;
      --panel-red:#e30000;
      --panel-grey:#b0b0b0;
      --header:#000;
      --score-bg:#fff;
      --text:#111;
      --btn-green:#1fa123;
      --btn-red:#d82424;
      --btn-grey:#9b9b9b;
      --timer-bg:#000;
      --timer-blue:#132a7a;
      --timer-amber:#ffb100;
    }
    body{
      margin:0; background:var(--bg); color:var(--text);
      font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
      display:flex; flex-direction:column; align-items:center; justify-content:flex-start;
    }

    .row{
      display:flex; justify-content:space-between; align-items:center;
      width:100%; max-width:1200px; margin:20px 0;
    }

    .team{
      width: 200px; height: 150px;
      background: var(--panel-red);
      border-radius: 4px;
      display:flex; flex-direction:column; align-items:center; justify-content:flex-start;
    }
    .team .header{
      width:100%; height:40px; background:var(--header); color:#fff;
      display:flex; align-items:center; justify-content:center;
      font-weight:700; font-size:20px;
      border-top-left-radius:4px; border-top-right-radius:4px;
    }
    .team .score{
      margin-top:20px;
      width: 80px; height: 50px; background:var(--score-bg);
      display:flex; align-items:center; justify-content:center;
      font-size:36px; font-weight:700; border-radius:4px;
      user-select:none; cursor:pointer;
    }
    .team.disabled {
      background: var(--panel-grey);
    }

    .side-controls{display:flex; flex-direction:column; gap:8px; margin-left:10px; margin-right:10px;}
    .side-controls .btn{width:100px; height:30px; background:#bcbcbc; color:#444; border:none; border-radius:3px; cursor:not-allowed; font-weight:600;}

    .center-controls{
      display:flex; flex-direction:column; align-items:center; gap:10px;
    }
    .main-timer{ background:var(--timer-bg); color:var(--timer-amber); padding:10px 24px; font-weight:800; font-size:32px; border-radius:4px;}
    .penalty-timer{ background:var(--timer-blue); color:#b6c8ff; padding:6px 14px; font-weight:800; font-size:18px; border-radius:4px;}
    .controls{ display:flex; gap:12px; }
    .controls button{ min-width:100px; height:36px; border:none; border-radius:4px; font-weight:700; color:#fff; cursor:pointer; }
    .start{ background:var(--btn-green)}
    .stop{ background:var(--btn-red)}

    .mini-timer{ background:var(--timer-bg); color:var(--timer-amber); padding:10px 24px; font-weight:800; font-size:28px; border-radius:4px;}
  </style>
</head>
<body>
  <!-- Top row -->
  <div class="row">
    <div class="team" data-team="A">
      <div class="header">Team A</div>
      <div class="score" data-score>0</div>
    </div>
    <div class="side-controls">
      <button class="btn" disabled>TOWEL</button>
      <button class="btn" disabled>Base</button>
    </div>

    <div class="center-controls">
      <div class="main-timer" id="mainTimer">05:00</div>
      <div class="penalty-timer" id="penaltyTimer">02:00</div>
      <div class="controls">
        <button class="start" id="startBtn">START</button>
        <button class="stop" id="stopBtn">STOP</button>
      </div>
    </div>

    <div class="side-controls">
      <button class="btn" disabled>TOWEL</button>
      <button class="btn" disabled>Base</button>
    </div>
    <div class="team" data-team="B">
      <div class="header">Team B</div>
      <div class="score" data-score>0</div>
    </div>
  </div>

  <!-- Bottom row -->
  <div class="row" style="justify-content:space-between;">
    <div class="team disabled" data-team="C">
      <div class="header">Team C</div>
      <div class="score" data-score>0</div>
    </div>
    <div class="mini-timer" id="miniTimer">05:00</div>
    <div class="team disabled" data-team="D">
      <div class="header">Team D</div>
      <div class="score" data-score>0</div>
    </div>
  </div>

  <script>
    function secondsToMMSS(s){
      const m = Math.floor(s/60).toString().padStart(2,'0');
      const sec = Math.floor(s%60).toString().padStart(2,'0');
      return `${m}:${sec}`;
    }

    let mainDur = 5*60;
    let penaltyDur = 2*60;

    let mainRemaining = mainDur;
    let penaltyRemaining = penaltyDur;

    let mainTick = null;
    let penaltyTick = null;

    const mainTimerEl = document.getElementById('mainTimer');
    const penaltyTimerEl = document.getElementById('penaltyTimer');
    const miniTimerEl = document.getElementById('miniTimer');

    function renderTimers(){
      mainTimerEl.textContent = secondsToMMSS(mainRemaining);
      penaltyTimerEl.textContent = secondsToMMSS(penaltyRemaining);
      miniTimerEl.textContent = secondsToMMSS(mainRemaining);
    }
    renderTimers();

    function stopAll(){
      if(mainTick){ clearInterval(mainTick); mainTick = null; }
      if(penaltyTick){ clearInterval(penaltyTick); penaltyTick = null; }
    }

    function startAll(){
      stopAll();
      mainTick = setInterval(()=>{
        if(mainRemaining>0){ mainRemaining--; renderTimers(); }
        else{ stopAll(); }
      },1000);

      penaltyTick = setInterval(()=>{
        if(penaltyRemaining>0){ penaltyRemaining--; renderTimers(); }
        else { clearInterval(penaltyTick); penaltyTick = null; }
      },1000);
    }

    document.getElementById('startBtn').addEventListener('click', startAll);
    document.getElementById('stopBtn').addEventListener('click', stopAll);

    mainTimerEl.addEventListener('click',()=>{
      mainRemaining = mainDur; penaltyRemaining = penaltyDur; renderTimers();
    });

    document.querySelectorAll('[data-score]').forEach(el=>{
      el.addEventListener('click', (e)=>{
        const team = el.textContent[0];
        let val = parseInt(el.textContent.slice(1),10);
        if(e.altKey){ val = Math.max(0, val-1); }
        else { val = val+1; }
        el.textContent = team + val;
      });
      el.addEventListener('contextmenu', (e)=>{ e.preventDefault(); const team = el.textContent[0]; let val = parseInt(el.textContent.slice(1),10); val = Math.max(0, val-1); el.textContent = team + val; });
    });

    window.addEventListener('keydown', (e)=>{
      if(e.key===' '){ e.preventDefault(); if(mainTick) stopAll(); else startAll(); }
      if(e.key==='r' || e.key==='R'){ mainRemaining = mainDur; penaltyRemaining = penaltyDur; renderTimers(); }
    });
  </script>
</body>
</html>
GhostFace
User
Beiträge: 2
Registriert: Freitag 22. August 2025, 19:39

@juwido Ah okay. Also kann ich wenn ich das Richtig verstanden habe, die einzelnen Elemente wie Team Felder als Frame schreiben,
diese mit pack anordnen und die Frames dann auf der UI mittels grid anordnen. Dann baue ich mir einfach ein 5x5 Grit,
so dass ich dann zwischen den Team Feldern auf der Y Achse weiterhin den abstand habe und packe die Buttons die unmittelbar
nebeneinander stehen ebenfalls in ein unsichtbares Frame um sie entsprechend auf dem Grid platzieren zu können? Also so wie ich es
auf dem Bild professionell mit Paint dargestellt habe? Bild

@Sirius3 Hmm, stimmt das wäre auch eine Option. An das hatte ich selbst auch noch nicht gedacht. Für die Anzeige,
welche in Projiziere wäre das an sich ein gute Idee, jedoch wird auch einiges an Steuerung etc. über GUI erledigt. Einerseits als Rückfallebene
als auch an Steuerungen wie Penaltys etc. Da wäre mir eine Software interne Lösung fast lieber. Aber für die Reine Anzeige, welche
ich dann an den Beamer übertrage wäre das schon auch ne gute Lösung, da ich dann einfach über einen Chromecast oder sowas
auf die HTML Datei auf dem Rechner zugreifen muss und somit kein Kabel oder sowas ziehen muss. Ich werde mir die Idee auf
jeden fall dankend im Hinterkopf behalten.
Benutzeravatar
noisefloor
User
Beiträge: 4202
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Durch Googeln ist es mir dann aufgefallen, dass es mit großer Wahrscheinlichkeit daran liegt, dass ich die Positionierung der Elemente mittels Place erledigt habe.
Genau. `place` platziert pixelgenau. Das funktioniert aber nur dann gut (und wirklich nur dann) wenn man sicher ist, dass sich die Auflösung des Fensters nie ändern. Also z.B. wenn man z.B. ein Display mit fixer Auslösung hat und es (für den Nutzer) keine Möglichkeit gibt, die Fenstergröße zu ändern. Was halt an "normalen" Computern, Tablets etc. nicht der Fall ist. Und auch nicht, wenn du ein externes Display anschließt, was eine andere Auflösung hat als dein Hauptdisplay.
Ich habe es nun mehrmals nachträglich versucht anders zu lösen und aufzubauen, so dass es auch auf verschiedenen Bildschirmen immer gleich aussieht und nicht teilweise so ist, dass Elemente abgeschnitten/ ineinander sind etc. habe es jedoch überhaupt nicht geschafft, ansatzweise ein ähnliches Resultat zu erzielen.
Das ist auch schwer bis unmöglich, wenn man große Unterschiede in der Auflösung hat. Das GUI Framework versucht halt immer irgendwie, alles darzustellen, egal wie. Wenn du tkinter benutzt ist halt noch zu bedenken, dass das aus einer Zeit stammt, als die Unterschiede zwischen min und max Auflösung viel kleiner waren als heute. Da gab es noch kein Full HD oder 4K oder 8K oder so.

Wenn technisch nichts dagegen spricht wäre ich auch beim Ansatz von @Sirius3, also HTML + CSS, weil das viel flexibler mit unterschiedlichen Auflösungen ist bzw. die Browser das deutlich besser hinbekommen. Natürlich das CSS nicht selber schreiben, sondern ein passendes CSS Framework nehmen, was ein Grid System hat. Bekannt und absoluter Mainstream ist z.B. Bootstrap CSS, es gibt auch auch noch reichlich andere CSS Frameworks.

Nachtrag:
jedoch wird auch einiges an Steuerung etc. über GUI erledigt.
HTML kennt Buttons und eine breite Auswahl an Eingabefeldern.

Gruß, noisefloor
Antworten