I struggle to understand why the window I'm doing with openGL stays black.
I don't see where I made a mistake in my code :
import com.jogamp.opengl.awt.GLCanvas
import com.jogamp.opengl.{GL, GLAutoDrawable, GLCapabilities, GLEventListener, GLProfile}
import javax.swing.{JFrame, WindowConstants}
class Game extends JFrame ("Just a window OMG.") with GLEventListener {
val profile: GLProfile = GLProfile.get(GLProfile.GL4)
val capabilities = new GLCapabilities(profile)
val canvas = new GLCanvas(capabilities)
this.setName("Just a window OMG.")
this.getContentPane.add(canvas)
this.setSize(800, 600)
this.setLocationRelativeTo(null)
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE)
this.setVisible(true)
this.setResizable(false)
canvas.requestFocusInWindow
def play(): Unit = {
}
override def display(drawable: GLAutoDrawable): Unit = {
val gl = drawable.getGL.getGL4
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
gl.glFlush()
}
override def dispose(drawable: GLAutoDrawable): Unit = {}
override def init(drawable: GLAutoDrawable): Unit = {
val gl = drawable.getGL.getGL4
gl.glClearColor(1f, 0f, 0f, 1.0f)
}
override def reshape(drawable: GLAutoDrawable, x: Int, y: Int, width: Int, height: Int): Unit = {}
}
object Main {
def main(args: Array[String]): Unit = {
val game = new Game()
game.play()
}
}
I also tried to put the glClear inside the display method and also put a glClearColor in the init method.
EDIT:
I found it.
Actually the display and init meth were never called.
The listener wasn't attached to the canvas and then it never received any event.
The problem is that I was missing the line
canvas.addGLEventListener(this)
just after the canvas initialisation.
(this line)
val canvas = new GLCanvas(capabilities)
(I'm answering my own question)
So actually the problem was that the display and init method were never called.
As far as I understood it, the GLEventListener is waiting for event and those would trigger the call of the init and display method.
The "thing" that would notice the GLEventListener is the canvas, yet my canvas and the GLEventListener weren't binded.
To do so I added the line
canvas.addGLEventListener(this)
Just after I initialized the canvas and it then I could notice the init and display method called.
Related
I am working on a todo list app using
scalajs,
cats (free monads), and
scalajs-react
When I am using a simple model like the code below, everything works like expected.
class TodoModel() {
private object State {
var todos = Seq.empty[Todo]
def mod(f: Seq[Todo] => Seq[Todo]): Callback = {
val newTodos = f(todos)
Callback(todos = newTodos)
}
}
def add(t: Todo): Callback = State.mod(_ :+ t)
def todos: Seq[Todo] = State.todos
}
Once I use the free monads from cats, I have an odd behaviour. The first click always inserts two todo entries. Every click afterwards works like expected. See the pictures below.
What is wrong here?
import cats.free.Free
import cats.free.Free.liftF
import japgolly.scalajs.react._
import japgolly.scalajs.react.vdom.html_<^._
import org.scalajs.dom
case class Todo(text: String)
sealed trait TodoModelOp[A]
case class Add(todo: Todo) extends TodoModelOp[Unit]
case class Todos() extends TodoModelOp[Seq[Todo]]
object FreeTodoModelOps {
// type alias for lifted TodoModelOp
type TodoModelOpF[A] = Free[TodoModelOp, A]
def add(Todo: Todo): TodoModelOpF[Unit] = liftF[TodoModelOp, Unit](Add(Todo))
def todos: TodoModelOpF[Seq[Todo]] = liftF[TodoModelOp, Seq[Todo]](Todos())
}
object StateInterpreter {
import cats.arrow.FunctionK
import cats.{ Id, ~> }
val interpet: TodoModelOp ~> Id = new (TodoModelOp ~> Id) {
val todos = scala.collection.mutable.ArrayBuffer.empty[Todo]
def apply[A](fa: TodoModelOp[A]): Id[A] = fa match {
case Add(todo) => todos += todo; ()
case Todos() => todos.toSeq
}
}
}
class TodoModel() {
import cats.instances.list._
import cats.syntax.traverse._
import FreeTodoModelOps._
def add(t: Todo): Callback = {
def program: TodoModelOpF[Unit] = for {
_ <- FreeTodoModelOps.add(t)
} yield ()
Callback(program.foldMap(StateInterpreter.interpet))
}
def todos: Seq[Todo] = {
def program: TodoModelOpF[Seq[Todo]] = for {
n <- FreeTodoModelOps.todos
} yield n
program.foldMap(StateInterpreter.interpet)
}
}
object TodoPage {
case class Props(model: TodoModel)
case class State(todos: Seq[Todo])
class Backend($: BackendScope[Props, State]) {
val t = Todo("a new todo")
def onSubmit(e: ReactEventFromInput) =
e.preventDefaultCB >>
$.modState(s => State(s.todos :+ t)) >>
$.props.flatMap(P => P.model.add(t))
def render(S: State) =
<.div(
<.form(
^.onSubmit ==> onSubmit,
<.button("Add #", S.todos.length + 1)),
<.ul(S.todos.map(t => <.li(t.text)): _*))
}
val component = ScalaComponent.builder[Props]("Todo")
.initialStateFromProps(p => State(p.model.todos))
.renderBackend[Backend]
.build
def apply(model: TodoModel) = component(Props(model))
}
object Test {
val model = new TodoModel()
def main(args: Array[String]): Unit = {
TodoPage.apply(model).renderIntoDOM(dom.document.getElementById("mount-node"))
}
}
empty, no click on button
first click on button
second click on button
In your first snippet there's a bug:
Here you've got a variable todos (inpure) which you're accessing in a pure context:
def mod(f: Seq[Todo] => Seq[Todo]): Callback = {
val newTodos = f(todos)
Callback(todos = newTodos)
Impurity should be in Callback. Even reading a variable outside of a Callback is unsafe, so it should be:
def mod(f: Seq[Todo] => Seq[Todo]): Callback =
Callback(todos = f(todos))
(See scalajs-react's Ref.scala an example of safely working with a variable.)
Secondly, with regards to your larger snippet, scalajs-react is very FP friendly but that's very unconventional way of trying to use it, and has some significant problems:
StateInterpreter.interpet isn't referentially-transparent; there's shared global state underlying that. Fails the FP test. Stops being a lawful natural transformation.
You're tracking two sets of identical state separately: the component state and the state in TodoModel (impure, fails the FP test). Not only is this approach redundant and runs the risk of the two states getting out-of-sync, but it also makes the component less reusable; imagine you decided to draw it twice on the same screen for the same data - they're going to go out of sync. Best to keep the component stateless and pure.
If you're going to transform a free structure into a component effect, it's best to transform it into a state monad, see here for an example.
It's really, really awesome that you're learning about free monads and scalajs-react. FP will make your entire program really, really easy to reason about and prevent confusing surprises in behaviour, but you've got to not cut any corners and make sure that you keep all of your code pure. Any impurity will render the entire stack all the way up to the entrypoint impure and remove those nice dependable FP properties from those layers. I'd suggest making everything as pure as possible using the points above as starting points, and then I think you'll find that the bug just disappears, or at least is very easy to then detect. Cheers
I have this piece of code, trying to build a timer that will decrease a given value in a TextField (which is supposed to contain minutes needed to finish a job, but those minutes will be given manually and then be decreased by this clock):
import scala.swing._
class ScalaTimer(val delay: Int) {
val tmr: javax.swing.Timer = new javax.swing.Timer(delay, null)
def start() = tmr.start()
def stop() = tmr.stop()
}
object Test33 { //extends SimpleSwingApplication {
val timer = new ScalaTimer(50)
timer.tmr.start
//def top = new MainFrame {
def main(args: Array[String]) {
timer.tmr.addActionListener(Swing.ActionListener(e => {
println(timer.delay - 1)
}))
}
//}
}
I don't get why it doesn't print anything when I use a main() method, but it prints the current given delay when I use a Frame :|
It won't print anything with your code as it stands because your application exits as soon as it's added the ActionListener, and before anything has had a chance to fire it!
Try adding
Thread.sleep(10000);
just before the end of your main method, and you'll find it'll print 49 repeatedly.
It works as it stands with a Frame because that prevents the application from terminating until the Frame is closed.
I have a text field which is supposed to hold some manualy given minutes, then I need this given number (these minutes) to be decreased by a timer (I already have configured a timer to give me ticks every 1 second), but I am struggling to find how I can do it simply; can it help if I try to use
scala.concurrent.duration._
frankly, I haven't take a look on it before. Or any other suggestion is welcomed.
My current solution, for somebody that may need it:
class ScalaTimer(val delay: Int) {
val tmr: javax.swing.Timer = new javax.swing.Timer(delay, null)
def start() = tmr.start()
def stop() = tmr.stop()
}
object Test33 { //extends SimpleSwingApplication {
val timer = new ScalaTimer(1000)
timer.start
var remainedtime: Int = 10
def main(args: Array[String]) {
timer.tmr.addActionListener(Swing.ActionListener(e => {
val tm = remainedtime - 1
remainedtime = tm
println(tm)
}))
Thread.sleep(10000);
}
Lets hope that I may use it now, as I want :)
I want to use this code to display generic Javafx Scene from my program
class JFXWindowDisplay(myScene:Scene) extends Application {
def start( stage: Stage) {
stage.setTitle("My JavaFX Application")
stage.setScene(myScene)
stage.show()
}
}
//OBJECT NEEDED TO RUN JAVAFX : http://stackoverflow.com/questions/12124657/getting-started-on-scala-javafx-desktop-application-development
object JFXWindowDisplay extends App {
override def main(args: Array[String]) {
Application.launch(classOf[JFXWindowDisplay], args: _*)
}
}
How can i pass Scene argument to the compagnon object ?
For example, i want to create a program which open a new javafx windows from scala script execution of this :
class myProgram() extends App {
val root = new StackPane
root.getChildren.add(new Label("Hello world!"))
val myScene = new Scene(root, 300, 300))
// then run ControlTest object with this scene
ControlTest(myScene)
}
You could prepare two or more traits each with his specific scene and then mix the one you need to the application class
trait SceneProvider {
def scene: Scene
}
trait Scene1 extends SceneProvider {
val root = new StackPane
root.getChildren.add(new Label("Hello world!"))
def scene = new Scene(root, 300, 300)
}
trait Scene2 extends SceneProvider {
val root = new StackPane
root.getChildren.add(new Label("Hello world 2!"))
def scene = new Scene(root, 300, 300)
}
trait JFXWindowDisplay {
self: SceneProvider =>
def start(stage: Stage) {
stage.setTitle("My JavaFX Application")
stage.setScene(scene)
stage.show()
}
}
class JFXWindowDisplay1 extends Application with JFXWindowDisplay with Scene1
class JFXWindowDisplay2 extends Application with JFXWindowDisplay with Scene2
object JFXMain extends App {
override def main(args: Array[String]) {
//here you chose an application class
Application.launch(classOf[JFXWindowDisplay1], args: _*)
}
}
EDIT: now this works, based on your comments.
I am trying to solve a problem given by the Book "Scala for the Impatient", which asked to implement java's BufferedInputStream as a trait. Here is my implementation,
trait Buffering {
this:InputStream =>
private[this] val bis = {
new JavaBufferedInputStream(this)
}
override def read = bis.read
override def read(byte:Array[Byte], off:Int, len:Int) = bis.read(byte, off, len)
override def available = bis.available
override def close() {
bis.close
}
override def skip(n:Long) = bis.skip(n)
}
def main(args:Array[String]) {
val bfis = new FileInputStream(new File("foo.txt")) with Buffering
println(bfis.read)
bfis.close
}
But this give me a java stackoverflow error, so what's wrong with it? Thanks!
It looks like you are getting a stack overflow where you don't expect one. The key to troubleshoot these is to look at the repeating cycle of the stack trace. It usually points to what is repeatedly allocating frames. Here it will show something like that:
at C.Buffering$class.read(C.scala:12)
at C.C$$anon$1.read(C.scala:23)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
at C.Buffering$class.read(C.scala:12)
at C.C$$anon$1.read(C.scala:23)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
at C.Buffering$class.read(C.scala:12)
So reading from bottom to top, it looks like your read(byte, ...) is calling bis.read(byte, ...) which is calling BufferedInputStream.read which is then calling your read(byte, ...) again.
It would appear that new BufferedInputStream(this) is calling read on the underlying InputStream but since the underlying this is your object that then delegates calls on bis we have infinite recursion.
I'm guessing that the author wants you to use the abstract override stackable modifications pattern where you can use super to refer to the right read method.
Maybe this is the answer. Just maybe from what i understood.
trait Buffering extends InputStream{
abstract override def read()=
{
println("Hello");
super.read()
}
}
val t = new ByteArrayInputStream("hello".getBytes()) with Buffering
I have been going through "Scala for the Impatient". Here is what I have as a solution to exercise 8 in chapter 10:
import java.io._
object BufferedInputStream extends App {
trait Buffering {
this: FileInputStream =>
val br = new BufferedInputStream(this)
}
def bufferedReader(f: String): Unit = {
val fis = new FileInputStream(f) with Buffering
var c = 0
var blen = 8192
var len = 0
var b = new Array[Byte](blen)
while (fis.br.available > 0) {
if (fis.br.available > blen) len = blen
else len = fis.br.available
c = fis.br.read(b, 0, len)
if (c == -1) return
print((for (i <- 0 to (c - 1)) yield b(i).toChar).mkString)
}
fis.br.close
fis.close
}
bufferedReader("webpagexample")
}