Hey,
I’m actually a designer, not a programmer.
That’s why my code is probably not very clear.
But I’m just trying to learn.
I haven’t done a build yet but the code isn’t working properly either.
Error: It is rendered immediately after each single digit input. If I have to enter 3 digits in the input field, do it slowly and always wait until the next digit is rendered and so on.
The calcualtion with variables are just for test, with out any sens.
I need the inputs be saved for the case the User updates browser, because the UI will have upto 30 input fields, and if they are restort to defualt it will be funy, because need put in again. But did manage that it works with backup.json.
Thans for hint with “set a wide layout”
My English is not so good, but I hope I could make my point understandable
I hoppe you can help me to solve this problem.
Python Code:
import json
import os
import streamlit as st
import streamlit.components.v1 as components
import base64
st.set_page_config(layout="centered")
# st.set_page_config(layout="wide")
# Backup-Datei
BACKUP_FILE = "backup.json"
def load_state_from_file():
if os.path.exists(BACKUP_FILE):
with open(BACKUP_FILE, "r") as f:
try:
return json.load(f)
except json.JSONDecodeError:
return {}
return {}
def save_state_to_file(state):
with open(BACKUP_FILE, "w") as f:
json.dump(state, f)
def get_image_base64(image_path):
with open(image_path, "rb") as img_file:
return base64.b64encode(img_file.read()).decode("utf-8")
def component_piston_variant(image_path, variable_values, key=None):
base64_image = get_image_base64(image_path)
_component_piston_variant = components.declare_component(
"component_piston_variant",
url="http://localhost:3001" # Entwicklermodus
)
result = _component_piston_variant(
base64Image=base64_image, variableValues=variable_values, key=key
)
return result
def main():
st.title("Interaktive Tabelle mit Bildhintergrund")
st.write("Änderungen werden gespeichert, wenn die Eingabe abgeschlossen ist.")
state = load_state_from_file()
# Standardwerte initialisieren
default_values = {
"variable_values1": 10,
"variable_values2": 5,
"variable_values3": 8,
"variable_values4": 2,
"variable_values5": 3,
"variable_values6": 1,
}
# Überprüfung und Initialisierung
for key, default_value in default_values.items():
if key not in state or not isinstance(state[key], (int, float)):
state[key] = default_value
# Bildpfad
image_path = r"C:\Users\104195\component_piston_variant\Stand_19_okt\sicherung\component_piston_variant\frontend\public\O-Ring-Hole.png"
# Aktuelle Werte
current_values = [
state["variable_values1"],
state["variable_values2"],
state["variable_values3"],
state["variable_values4"],
state["variable_values5"],
state["variable_values6"],
]
# Benutzerinteraktion
updated_values = component_piston_variant(image_path, current_values)
if updated_values is not None:
# Werte aktualisieren
for i, key in enumerate(default_values.keys()):
state[key] = updated_values[i]
save_state_to_file(state)
# Berechnungen
st.write("### Ergebnisse der Berechnungen")
sum1 = state["variable_values1"] + state["variable_values2"]
product1 = state["variable_values1"] * state["variable_values2"]
difference = state["variable_values1"] - state["variable_values6"]
double_value = state["variable_values2"] * 2
# Ergebnisse anzeigen
st.write(f"**Summe der Variablenwerte (1 + 2):** {sum1}")
st.write(f"**Produkt der Variablenwerte (1 * 2):** {product1}")
st.write(f"**Unterschied (Variable 1 - Variable 6):** {difference}")
st.write(f"**Doppelter Wert von Variable 2:** {double_value}")
if __name__ == "__main__":
main()
React Component code:
import React from "react";
import { Streamlit, StreamlitComponentBase, withStreamlitConnection } from "streamlit-component-lib";
import "./ComponentPistonVariant.css"; // Separate CSS-Datei importieren
interface Props {
args: {
base64Image: string;
variableValues: number[]; // Einzelne Werte für 6 Variablen
};
width: number; // Erwartete Eigenschaft
disabled: boolean; // Erwartete Eigenschaft
}
interface State {
d1_UpT: number;
d1: number;
d1_LoT: number;
d2_UpT: number;
d2: number;
d2_LoT: number;
}
class ComponentPistonVariant extends StreamlitComponentBase<State> {
public constructor(props: Props) {
super(props);
// Initialisieren der 6 Variablen mit den Werten von Streamlit
this.state = {
d1_UpT: this.props.args.variableValues[0],
d1: this.props.args.variableValues[1],
d1_LoT: this.props.args.variableValues[2],
d2_UpT: this.props.args.variableValues[3],
d2: this.props.args.variableValues[4],
d2_LoT: this.props.args.variableValues[5],
};
}
private onValueChange = (name: string, value: string): void => {
// Wert aktualisieren
const newValue = Number(value);
this.setState(
{
[name]: newValue,
} as Pick<State, keyof State>,
() => {
// Alle 6 Variablen an Streamlit senden
Streamlit.setComponentValue([
this.state.d1_UpT,
this.state.d1,
this.state.d1_LoT,
this.state.d2_UpT,
this.state.d2,
this.state.d2_LoT,
]);
}
);
};
public render() {
const { base64Image } = this.props.args;
const imageUrl = `data:image/png;base64,${base64Image}`;
return (
<div className="background-container">
<img src={imageUrl} alt="Background" className="background-image" />
{/* Erste Tabelle */}
<div className="table-container table-left">
<table>
<tbody>
<tr>
<td>d1-UpT</td>
<td>
<input
type="number"
value={this.state.d1_UpT}
onChange={(e) => this.onValueChange("d1_UpT", e.target.value)}
/>
</td>
</tr>
<tr>
<td>d1</td>
<td>
<input
type="number"
value={this.state.d1}
onChange={(e) => this.onValueChange("d1", e.target.value)}
/>
</td>
</tr>
<tr>
<td>d1-LoT</td>
<td>
<input
type="number"
value={this.state.d1_LoT}
onChange={(e) => this.onValueChange("d1_LoT", e.target.value)}
/>
</td>
</tr>
</tbody>
</table>
</div>
{/* Zweite Tabelle */}
<div className="table-container table-right">
<table>
<tbody>
<tr>
<td>d2-UpT</td>
<td>
<input
type="number"
value={this.state.d2_UpT}
onChange={(e) => this.onValueChange("d2_UpT", e.target.value)}
/>
</td>
</tr>
<tr>
<td>d2</td>
<td>
<input
type="number"
value={this.state.d2}
onChange={(e) => this.onValueChange("d2", e.target.value)}
/>
</td>
</tr>
<tr>
<td>d2-LoT</td>
<td>
<input
type="number"
value={this.state.d2_LoT}
onChange={(e) => this.onValueChange("d2_LoT", e.target.value)}
/>
</td>
</tr>
</tbody>
</table>
</div>
</div>
);
}
}
export default withStreamlitConnection(ComponentPistonVariant);
CCS Kode:
.background-container {
position: relative;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden; /* Verhindert Überlauf */
}
.background-image {
width: 100%;
height: auto;
object-fit: cover; /* Bild passt sich an den Container an */
}
.table-container {
position: absolute;
}
.table-left {
top: 39.8%; /* Originale Position */
left: 43%; /* Originale Position */
transform: scale(0.7); /* Tabellen um 30% kleiner machen */
}
.table-right {
top: 5%; /* Originale Position */
left: 37%; /* Originale Position */
transform: scale(0.7); /* Tabellen um 30% kleiner machen */
}
table {
border-collapse: collapse; /* Entfernt Leerraum zwischen Zellen */
width: auto; /* Nur so breit wie nötig */
}
th, td {
border: 1px solid #000; /* Dünne Rahmen */
padding: 0px; /* Kein zusätzlicher Innenabstand */
text-align: center; /* Zentrierter Text */
min-width: 30px; /* Mindestbreite */
font-size: 12px; /* Kleinere Schriftgröße */
line-height: 1; /* Weniger vertikaler Platz */
}
input[type="text"], input[type="number"] {
width: 60px; /* Platz für etwa 6 Zeichen */
max-width: 100%; /* Passt sich an den Container an */
border: 1px solid #ccc; /* Rahmen */
border-radius: 2px; /* Ecken abgerundet */
text-align: center; /* Zentrierter Text */
padding: 1px; /* Minimales Padding */
overflow: hidden; /* Verhindert Überlauf */
text-overflow: ellipsis; /* Lässt überschüssigen Text mit "..." auslaufen */
white-space: nowrap; /* Verhindert Zeilenumbrüche */
-moz-appearance: textfield; /* Entfernt Pfeile in Firefox */
-webkit-appearance: none; /* Entfernt Pfeile in Chrome/Safari */
appearance: none; /* Entfernt Pfeile in modernen Browsern */
}