I'm trying to plot some sensor data that's being read in through the serial port. I found this Processing example code of a 2D plotter, and I'm trying to alter it to work for my application.
The programming is a bit over my head though. I can see that it's getting data for the three lines from the three equation classes. I'd like to replace the part where is reads the mouseX with a variable or something that points to the newest sensor update. The sensor data is continuously updated in the void Draw() loop.
/**
* RollingGraph
* This sketch makes ise of the RollingLine2DTrace object to
* draw a dynamically updated plot.
*/
import org.gwoptics.graphics.graph2D.Graph2D;
import org.gwoptics.graphics.graph2D.traces.ILine2DEquation;
import org.gwoptics.graphics.graph2D.traces.RollingLine2DTrace;
class eq implements ILine2DEquation{
public double computePoint(double x,int pos) {
return mouseX;
}
}
class eq2 implements ILine2DEquation{
public double computePoint(double x,int pos) {
return mouseY;
}
}
class eq3 implements ILine2DEquation{
public double computePoint(double x,int pos) {
if(mousePressed)
return 400;
else
return 0;
}
}
RollingLine2DTrace r,r2,r3;
Graph2D g;
void setup(){
size(600,300);
r = new RollingLine2DTrace(new eq() ,100,0.1f);
r.setTraceColour(0, 255, 0);
r2 = new RollingLine2DTrace(new eq2(),100,0.1f);
r2.setTraceColour(255, 0, 0);
r3 = new RollingLine2DTrace(new eq3(),100,0.1f);
r3.setTraceColour(0, 0, 255);
g = new Graph2D(this, 400, 200, false);
g.setYAxisMax(600);
g.addTrace(r);
g.addTrace(r2);
g.addTrace(r3);
g.position.y = 50;
g.position.x = 100;
g.setYAxisTickSpacing(100);
g.setXAxisMax(5f);
}
void draw(){
background(200);
g.draw();
}
Not exactly sure if that code you have is what you need, but here is a simple program that takes in serial input and makes a line graph. Hope this helps.
import processing.serial.*;
Serial myPort;
int x = 0;
void setup() {
size(600, 400);
println(Serial.list()); //list of available serial ports
String portName = Serial.list()[0]; //replace 0 with whatever port you want to use.
myPort = new Serial(this, portName, 9600);
}
void draw() {
}
void serialEvent(Serial myPort) {
int inByte = myPort.read();
println(inByte);
stroke(90, 76, 99);
//vertical line with height varying according to input
line(x, height, x, height - inByte);
if (x >=width) {
x=0;
background(0);
}
x++;
}
Related
I have an application with qt creator that gets geocoordinate data and shows it on the map.it works fine with just one connection but when it comes to having more than once makes it a riddle.
I want to get data in a loop from several qtcp connections with different addresses and ports then put data in separated lists and after reading the list of each connection geodata add separate layers on a map in different threads which updates every 3 seconds while all of them getting data concurrently from the network packets. suppose I have many different gps receivers to gather data of their location I want to integrate it on the map.
here is my code sample:
1.define list of servers that qtcp client should be connected:
globals.cpp
#define PACKET 50
struct Connects{
static QMap<QString,int> list()
{
QMap<QString,int> m;
m["sender1.com"] = 4456;
m["sender2.com"] = 4457;
m["sender3.com"] = 4458;
return m;
}
static const QMap<QString,int> myMap;
};
QMap<QString, int> const Connects::myMap = list();
2.main window to launch map:
main.cpp
void add_layer(MarbleWidget *mapWidget,MainWindow *window,Client *client,QTimer *timer ){
//get data and append to a list every 3 sec
timer = new QTimer;
QObject::connect(timer,SIGNAL(timeout()),window,SLOT(next_client()));
QObject::connect(client,SIGNAL(Client_Connected()),window,SLOT(online_slot()));
timer->start(3000);
// Add New Layer based on positions in the list
MPaintLayer* layer = new MPaintLayer(mapWidget);
for(int j = 0; j < client->data.count(); ++j){
layer->setPosition(client->data.at(j).Lat,client->data.at(j).Lon);
}
mapWidget->addLayer(layer);
}
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
// Load Marble
MarbleWidget *mapWidget = new MarbleWidget;
mapWidget->show();
//iterate over connections address and port list
QMapIterator<QString,int> i(Connects::myMap);
while (i.hasNext()) {
i.next();
client = new Client;
client->ConnectToServer(i.key(),i.value());
//make thread pool and create new thread for adding each layer
QThreadPool pool;
QFuture<void> tr;
tr = QtConcurrent::run(&pool,add_layer,mapWidget,this,client,timer);
}
}
void MainWindow::online_slot()
{
//fetch data from the buffer and separate each entity based on size
while (client->GetLanBufferSize() >= PACKET) {
client->ReadData((char*)buffer,PACKET);
double lat,lon;
memcpy(&lat,&buffer[8],sizeof(double));
memcpy(&lon,&buffer[16],sizeof(double));
//put buffer data to target list which is defined in client
Target trg;
client->data.append(trg);
}
//remove has-readed data
for (int var = 0; var < client->data.count(); ++var) {
client->data.removeAt(var);
var--;
}
}
3.declare class for add or update a new layer based on recieved data on the map:
paintlayer.cpp
MPaintLayer::MPaintLayer(MarbleWidget* widget)
{
S_N = QPixmap(":/mode-s.png");
}
bool MPaintLayer::render( GeoPainter *painter,ViewportParams *viewport,
const QString& renderPos, GeoSceneLayer * layer )
{
//throw a tiny png file on map based on retrieved locations
for (int var = 0; var < pos.count(); ++var) {
painter->drawPixmap(pos[var],S_N));
}
return true;
}
void MPaintLayer::setPosition(double lat,double lon)
{
pos.append(GeoDataCoordinates(lat,lon,0,GeoDataCoordinates::Degree));
}
5.define a class for the format of received data:
client.h
class Target
{
public:
Target()
{
Lat = Lon = 0;
}
double Lat,Lon;
GeoDataCoordinates Position;
void update(double lat,double lon)
{
Lat = lat;
Lon = lon;
Position = GeoDataCoordinates(Lon,Lat,0,GeoDataCoordinates::Degree);
}
};
6.declare class for making new qtcp connection and receive data:
client.cpp
Client::Client(QObject *parent) : QObject(parent)
{
socket = new QTcpSocket(this);
connect(socket, SIGNAL(connected()),this, SLOT(on_connected()));
}
void Client::on_connected()
{
connect(socket, SIGNAL(disconnected()),this, SLOT(on_Disconnected()));
socket->setReadBufferSize(12e6);
emit Client_Connected();
}
bool Client::ReadData(char *buffer, int Leanth)
{
socket->read(buffer , Leanth);
return true;
}
int Client::GetLanBufferSize()
{
return socket->bytesAvailable();
}
void Client::on_Disconnected()
{
emit Client_DisConnected();
}
void Client::ConnectToServer(QString Address , int Port)
{
socket->connectToHost(Address, Port);
server = Address;
server_Port = Port;
}
the data format which is received from the senders is location of moving object something like this:
35.51243 51.22478
35.51260 51.22667
35.69270 51.03961
what is the best practice solution? because it shows nothing on the map. when I used hard code, it showed layers equivalent to each connection but reading stream of data is challengeable.
any clue would be appreciated.
You are not using QTcpSocket in its proper way.
In your Client class, you can handle all reading stuff and you won't even need those while loops. Use QIODevice::readyRead() signal and QIODevice::read(char *data, qint64 maxSize) method inside a slot which should read data and parse it.
The problem here is that it's not guaranteed that those data will be received with alignments happening on the sender side. For example, if you send >>>SOME_LENGTHY_DATA<<< from the sender, QTcpSocket may emit readyRead() signal two times and you can read >>>SOME_LENG and THY_DATA<<< in two different calls to your reading slot.
So, you should take care of parsing your data as data is coming in byte by byte.
You are free to buffer the incoming data somewhere in your class or just use the QTcpSocket internal buffer. You should really take care of separating message chunks that are coming in.
Here is an implementation of Client. I use QPointF to store point instead of your Target class because I don't know what it is. You are free to create your own class and append it to Client::data based on parsed lat/lon. I did not test the code but it should work.
I'm not sure if you ever need concurrency with this implementation but you won't need one IMHO.
//Client.h
class Client : public QTcpSocket
{
Q_OBJECT
public:
explicit Client(QObject *parent = nullptr);
private:
QString serverAddress;
int serverPort;
QList<QPointF> data; //you can use your own type, just for test
QByteArray lastLine;
void parseData();
signals:
void Client_Connected();
public slots:
void connectToServer(const QString& address, quint16 port);
void processData();
};
//Client.cpp
#include "client.h"
Client::Client(QObject *parent) : QTcpSocket (parent)
{
// we don't really want Client_Connected signal!
// you can use QTcpSocket::connected signal
connect(this, SIGNAL(connected()),this, SIGNAL(Client_Connected()));
// readyRead will be emitted when there is data in buffer to be read
connect(this, SIGNAL(readyRead()),this, SLOT(processData()));
}
void Client::parseData()
{
QString str(lastLine);
str = str.trimmed();
QStringList parts = str.split(" ",QString::SkipEmptyParts);
if(parts.count()==2){
bool success = true;
double latitude = success ? parts[0].toDouble(&success) : 0;
double longitude = success ? parts[1].toDouble(&success) : 0;
if(success)
data.append(QPointF(longitude,latitude));
}
}
void Client::connectToServer(const QString& address, quint16 port)
{
data.clear();
lastLine.clear();
serverPort = port;
serverAddress = address;
this->connectToHost(address,port);
}
void Client::processData()
{
QByteArray d = this->readAll();
for(int i = 0 ; i < d.count() ; ++i){
if(d.at(i)=='\r')
{
parseData();
lastLine.clear();
}
else
lastLine.append(d.at(i));
}
}
I created 2 libraries to use in my Arduino code. One is a HwSwitch library, the other is a HwServo library which uses the HwSwitch library.
HwSwitch Library:
HwSwitch::HwSwitch(String switchName, int switchPort, int inputType, int pressedState)
{
Name = switchName;
SwitchPort = switchPort;
_pressedState = pressedState;
_lastCheckMillis = 0;
pinMode(switchPort, inputType);
_lastPinState = digitalRead(SwitchPort);
}
bool HwSwitch::IsPressed()
{
int currentPinState = GetPinState();
return currentPinState == _pressedState;
}
bool HwSwitch::SwitchStateChanged()
{
int currentPinState = GetPinState();
if (_lastPinState != currentPinState)
{
Serial.println("---");
Serial.println("1. Now: " + String(currentPinState) + " - Prev: " + String(_lastPinState));
_lastPinState = currentPinState;
Serial.println("2. Now: " + String(currentPinState) + " - Prev: " + String(_lastPinState));
return true;
}
return false;
}
int HwSwitch::GetPinState()
{
unsigned long ms = millis();
if ((ms - _lastCheckMillis) < 50)
{
return _lastPinState;
}
_lastCheckMillis = ms;
return digitalRead(SwitchPort);
}
HwServo Library:
HwServo::HwServo(int servoPort, int zeroPoint, HwSwitch limitSwitch)
{
_servo.attach(servoPort);
_servo.write(zeroPoint);
ServoPort = servoPort;
ZeroPoint = zeroPoint;
LimitSwitch = limitSwitch;
}
void HwServo::RotateUp()
{
_servo.write(ZeroPoint + UP);
}
void HwServo::RotateDown()
{
if (!LimitSwitch.IsPressed())
{
_servo.write(ZeroPoint + DOWN);
}
}
void HwServo::Stop()
{
_servo.write(ZeroPoint);
}
And this is how I initialized it in the Arduino code:
HwServo HwServos[] = {
HwServo(9, 94, HwSwitch("S1", 14, INPUT_PULLUP, HIGH)),
HwServo(5, 90, HwSwitch("S2", 8, INPUT_PULLUP, HIGH)),
};
void setup() { }
void loop() {
for(int i = 0; i < 2; i++)
{
HwServo hwServo = HwServos[i];
if (hwServo.LimitSwitch.SwitchStateChanged())
{
SendSwitchStateUpdate(hwServo.LimitSwitch);
if (hwServo.LimitSwitch.IsPressed())
{
hwServo.Stop();
}
}
}
}
Now finally to the problem! As you can see in the HwSwitch library I output some data using Serial.println. Here I can see that _lastPinState is successfully updated, but gets reset after every loop. However, when I create a HwSwitch directly and use it, _lastPinState is not reset. In other words, the resetting of the value only seems to occur when the HwSwitch library is used inside the HwServo library.
Appearently this has something to do with the pointers? I am probably initializing my classes incorrectly, but I have no idea how to fix it. Anyone that can help with (and preferably explain) this issue?
I don't have my Arduino on me right now, but I took look and re-wrote your code, added the omitted constructors at my best guess, and got it to compile. There were some things which needed corrected. I'm sure there are other ways, but this is what I did.
For complete code, go here.
First, I created some pointers to objects I'd like to stick around, like so:
HwServo *HwServos[2];
HwSwitch *s1;
HwSwitch *s2;
HwServo *sv1;
HwServo *sv2;
Now each is reserved in memory on the Arduino.
Now, construct the objects in setup():
void setup() {
s1 = new HwSwitch("S1", 14, INPUT_PULLUP, HIGH);
s2 = new HwSwitch("S2", 8, INPUT_PULLUP, HIGH);
sv1 = new HwServo(9, 94, *s1);
sv2 = new HwServo(5, 90, *s2);
//Now, since you're going through an array:
HwServos[0] = sv1;
HwServos[1] = sv2;
}
Use that setup function!!! Maybe not always necessary, or in some cases even recommended, but it's nice to collect things which only need created once there, especially is this case.
Note that new was not used inside the scope of either object, but rather in the scope of the program... So no fancy destructors in your objects are required. Normally, you'd worry about deleting them all before program termination (or whenever best suited), but in Arduino's case, it'll just lose power and kill everything anyway.
You should change your class definitions to this:
class HwSwitch {
public:
String Name;
int SwitchPort;
int _pressedState;
int _lastCheckMillis;
int _lastPinState;
HwSwitch(String, int, int, int);
bool IsPressed();
bool SwitchStateChanged();
int GetPinState();
};
class HwServo {
public:
HwServo();
HwServo(int, int, HwSwitch &);
int ServoPort;
int ZeroPoint;
HwSwitch & LimitSwitch;
void RotateUp();
void RotateDown();
void Stop();
Servo _servo;
};
Note: I made everything public, feel free to move private stuff back to private if you wish.
I changed the constructors to:
HwSwitch::HwSwitch(String switchName, int switchPort, int inputType, int pressedState)
{
Name = switchName;
SwitchPort = switchPort;
_pressedState = pressedState;
_lastCheckMillis = 0;
pinMode(switchPort, inputType);
_lastPinState = digitalRead(SwitchPort);
}
HwServo::HwServo(int servoPort, int zeroPoint, HwSwitch &limitSwitch)
{
_servo.attach(servoPort);
_servo.write(zeroPoint);
ServoPort = servoPort;
ZeroPoint = zeroPoint;
LimitSwitch = limitSwitch;
}
And I modified loop() like so:
void loop() {
// put your main code here, to run repeatedly:
for(int i = 0; i < 2; i++)
{
if (HwServos[i]->LimitSwitch.SwitchStateChanged())
{
SendSwitchStateUpdate(HwServos[i]->LimitSwitch);
if (HwServos[i]->LimitSwitch.IsPressed())
{
HwServos[i]->Stop();
}
}
}
}
In my window there is a circle. I have implemented the void MouseClicked() method to take effect on the mouse click event. That means only clicking inside the circle should change the color of the circle and do the corresponding operation.
But the problem is wherever I click (even outside the circle), it changes the color of the circle. So I understand that the mouseClicked() method isn't stable. How do I fix this?
My code in processing:
int colorValue = 0;
void setup() {
size(450, 255);
background(204);
}
void draw() {
fill(colorValue);
ellipse(56, 46, 55, 55);
}
void mouseClicked() {
if (colorValue == 0) {
colorValue = 255;
} else {
colorValue = 0;
}
}
You aren't doing any check for whether the mouse is in the circle. You could use the dist() function to help with that:
int colorValue = 0;
float circleX = 56;
float circleY = 46;
float circleR = 55;
void setup() {
size(450, 255);
background(204);
ellipseMode(RADIUS);
}
void draw() {
fill(colorValue);
ellipse(circleX, circleY, circleR, circleR);
}
void mouseClicked() {
if(dist(mouseX, mouseY, circleX, circleY) < circleR){
if (colorValue == 0) {
colorValue = 255;
} else {
colorValue = 0;
}
}
}
In this program I have built a QPropertyanimation and add to it my item and pos() property.
I override KeyPressEvent. And with using of keys consist of j, f, z item go forward ,go back and jump.
According gravity when item jump should fall. For this purpose I call down function. But item just once jump don't fall. I also have another problem: when the first press j and f (forward and back) item animate desirably but for next times item go forward and go back all of scene.
I mean It should animated for example 40 pixel but It animated 800 pixel.
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
QPoint start;
QPoint end;
~MainWindow();
private:
QGraphicsView* view;
QGraphicsScene* scene;
void keyPressEvent(QKeyEvent* k);
MyQgraphicsObject* m;
QPropertyAnimation* pr;
QElapsedTimer* timer;
int f;
int u;
int b;
void forward();
void up();
void back();
void down();
};
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
view=new QGraphicsView;
scene=new QGraphicsScene;
m=new MyQgraphicsObject;
pr=new QPropertyAnimation(m,"pos");
view->setScene(scene);
view->resize(800,800);
view->setFixedSize(800,800);
setCentralWidget(view);
scene->addItem(m);
start= QPoint(0,0);
f=30;
u=-30;
b=-30;
}
void MainWindow::keyPressEvent(QKeyEvent *k)
{
switch (k->key()) {
case Qt::Key_J: {
forward();
break;
}
case Qt::Key_Z: {
up();
down();
break;
}
case Qt::Key_F: {
back();
break;
}
default:
break;
}
}
void MainWindow::forward()
{
end.setX(f);
pr->setEndValue(end);
pr->setDuration(1000);
pr->setEasingCurve(QEasingCurve::Linear);
pr->start();
f+=40;
}
void MainWindow::up()
{
end.setY(u);
pr->setEndValue(end);
pr->setDuration(1000);
pr->setEasingCurve(QEasingCurve::Linear);
pr->start();
u-=30;
pr->pause();
}
void MainWindow::back()
{
end.setX(b);
pr->setEndValue(end);
pr->setDuration(1000);
pr->setEasingCurve(QEasingCurve::Linear);
pr->start();
b-=40;
}
void MainWindow::down()
{
u+=30;
end.setY(u);
pr->setEndValue(end);
pr->setDuration(1000);
pr->setEasingCurve(QEasingCurve::Linear);
pr->start();
}
You should not use resize and setFixedSize on view because you use it in setCentralWidget and its size will be managed by the layout. You should use setFixedSize on main window instead.
Animations are asynchonous. For example, when you call up(); down(), these functions will be executed without 1-second pause. Also, starting animation when it's already started has no effect.
Usually animations are used in such way when you know exactly where you need object to move in the next second. It's complicated to receive directives from user and change object's trajectory when the animation is already performing.
Here is an example showing correct use of animations for this task. Object can receive one directive (forward, back or jump) per second, and according animation will be performed in the next second.
Header:
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
QGraphicsView* view;
QGraphicsScene* scene;
void keyPressEvent(QKeyEvent* k);
QGraphicsObject* object;
QPropertyAnimation* animation;
QPointF pos;
double speed;
enum Command {
command_none, command_jump, command_forward, command_back
};
Command next_command;
private slots:
void timeout();
};
Source:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
view = new QGraphicsView;
scene = new QGraphicsScene;
object = scene->addWidget(new QPushButton("test"));
object->setPos(0, -object->boundingRect().height());
animation = new QPropertyAnimation(object,"pos");
animation->setDuration(1000);
view->setScene(scene);
setFixedSize(800,800);
scene->addRect(-500, -200, 1000, 200);
setCentralWidget(view);
scene->addItem(object);
next_command = command_none;
speed = 100;
QTimer* timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(timeout()));
timer->start(1000);
}
MainWindow::~MainWindow() {}
void MainWindow::keyPressEvent(QKeyEvent *k)
{
switch (k->key()) {
case Qt::Key_J: {
next_command = command_forward;
break;
}
case Qt::Key_Z: {
next_command = command_jump;
break;
}
case Qt::Key_F: {
next_command = command_back;
break;
}
default:
break;
}
}
void MainWindow::timeout() {
//fall
if (pos.y() < 0) {
pos.setY(pos.y() + speed);
if (pos.y() >= 0) {
pos.setY(0);
}
}
//action
switch(next_command) {
case command_forward:
pos.setX(pos.x() + speed);
break;
case command_back:
pos.setX(pos.x() - speed);
break;
case command_jump:
if (pos.y() == 0) {
pos.setY(pos.y() - speed);
}
break;
default:
break;
}
next_command = command_none;
animation->stop();
animation->setEndValue(pos - QPointF(0, object->boundingRect().height()));
animation->start();
}
here is my code
public class SimpleJoglApp extends JFrame {
public static void main(String[] args) {
final SimpleJoglApp app = new SimpleJoglApp();
// show what we've done
SwingUtilities.invokeLater(new Runnable() {
public void run() {
app.setVisible(true);
}
});
}
public SimpleJoglApp() {
// set the JFrame title
super("Test App");
// kill the process when the JFrame is closed
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// only two JOGL lines of code ... and here they are
GLCanvas glcanvas = new GLCanvas();
glcanvas.addGLEventListener(new SecondGLEventListener());
// add the GLCanvas just like we would any Component
getContentPane().add("Center", glcanvas);
setSize(500, 300);
}
public void centerWindow(Component frame) {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = frame.getSize();
if (frameSize.width > screenSize.width) {
frameSize.width = screenSize.width;
}
if (frameSize.height > screenSize.height) {
frameSize.height = screenSize.height;
}
frame.setLocation((screenSize.width - frameSize.width) >> 1, (screenSize.height - frameSize.height) >> 1);
}
public class SecondGLEventListener implements GLEventListener {
/**
* Interface to the GLU library.
*/
private GLU glu;
public void init(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
glu = new GLU();
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
gl.glViewport(0, 0, 500, 300);
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
glu.gluOrtho2D(0.0, 500.0, 0.0, 300.0);
}
/**
* Take care of drawing here.
*/
public void display(GLAutoDrawable drawable) {
float red = 0.0f;
float green = 0.0f;
float blue = 0.0f;
GL gl = drawable.getGL();
gl.glClear(GL.GL_COLOR_BUFFER_BIT);
gl.glPointSize(20.0f);
for (int i = 0; i < 10; i++) {
red -= .09f;
green -= .12f;
blue -= .15f;
if (red < 0.50) {
red = 0.5f;
}
if (green < 0.15) {
green = 0.5f;
}
if (blue < 0.15) {
blue = 0.5f;
}
gl.glPushMatrix();
gl.glColor3f(red, green, blue);
gl.glTranslatef(10.0f, 500.0f, 0.0f); // Move left 1.5 units, up 1.5 units, and back 8 units
gl.glBegin(GL.GL_QUADS); // Begin drawing quads
gl.glVertex3f((10f * i) + 10, 20.0f, 0.0f); // Top left vertex
gl.glVertex3f((40f * i) + 10, 20f, 0.0f); // Top right vertex
gl.glVertex3f((40f * i) + 10, -20f, 0.0f); // Bottom right vertex
gl.glVertex3f((10f * i) + 10, -20.0f, 0.0f); // Bottom left vertex
gl.glEnd();
gl.glPopMatrix();
}
}
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {}
public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {}
}
}
`
//~ Formatted by Jindent --- http://www.jindent.com
the code always produces the following error
Error: Could not find or load main class org.yourorghere.SimpleJoglApp
Java Result: 1
What am i doing wrong?
You never set the jframe.setvisible(true);
Also: Error: Could not find or load main class org.yourorghere.SimpleJoglApp Java Result: 1
has nothing to do with java. Just fix your classes set up.