I'm trying to build a room database app with Kotlin. Database part is ok. I need to create adapter to show database data in Recyclerview. But I can't use the holder command. I think it might be related to "Kotlinx.Synthetic has been deprecated". I want to introduce textviews id's to adapter. When i try "holder.itemView.id_txt.text = currentItem.id.toString()" it does not recognize "id_txt.text". Can you help with introduce the custom row's textview ids to adapter. Thank you.
User.kt
import androidx.room.Entity
import androidx.room.PrimaryKey
#Entity(tableName = "user_table")
data class User(
#PrimaryKey(autoGenerate = true)
val id: Int,
val firstName: String,
val lastName: String,
val age: String
)
UserDao.kt
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
#Dao
interface UserDao {
#Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun addUser(user: User)
#Query("SELECT * FROM user_table ORDER BY id ASC")
fun readAllData(): LiveData<List<User>>
}
UserDatabase.kt
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
#Database(entities = [User::class], version = 1, exportSchema = false)
abstract class UserDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
companion object {
#Volatile
private var INSTANCE: UserDatabase? = null
fun getDatabase(context: Context): UserDatabase{
val tempInstance = INSTANCE
if(tempInstance != null){
return tempInstance
}
synchronized(this){
val instance = Room.databaseBuilder(
context.applicationContext,
UserDatabase::class.java,
"user_database"
).build()
INSTANCE = instance
return instance
}
}
}
}
UserRepository.kt
import androidx.lifecycle.LiveData
class UserRepository(private val userDao: UserDao) {
val readAllData: LiveData<List<User>> = userDao.readAllData()
suspend fun addUser(user: User){
userDao.addUser(user)
}
}
UserViewModel.kt
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class UserViewModel(application: Application): AndroidViewModel(application) {
private val readAllData: LiveData<List<User>>
private val repository: UserRepository
init {
val userDao = UserDatabase.getDatabase(application).userDao()
repository = UserRepository(userDao)
readAllData = repository.readAllData
}
fun addUser(user: User){
viewModelScope.launch(Dispatchers.IO) {
repository.addUser(user)
}
}
}
AddFragment.kt
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import com.example.basehw.R
import com.example.basehw.data.UserViewModel
import com.example.basehw.databinding.FragmentAddBinding
import android.text.TextUtils
import android.widget.Toast
import com.example.basehw.data.User
class AddFragment : Fragment() {
private lateinit var mUserViewModel: UserViewModel
private var _binding: FragmentAddBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
_binding = FragmentAddBinding.inflate(inflater, container, false)
mUserViewModel = ViewModelProvider(this).get(UserViewModel::class.java)
binding.addBtn.setOnClickListener{
insertDataToDatabase()
}
return binding.root
}
private fun insertDataToDatabase() {
val firstName = binding.addFirstNameEt.text.toString()
val lastName = binding.addFirstNameEt.text.toString()
val age = binding.addAgeEt.text.toString()
if(inputCheck(firstName, lastName, age)){
// Create User Object
val user = User(
0,
firstName,
lastName,
age
)
// Add Data to Database
mUserViewModel.addUser(user)
Toast.makeText(requireContext(), "Successfully added!", Toast.LENGTH_LONG).show()
// Navigate Back
findNavController().navigate(R.id.action_addFragment_to_listFragment)
}else{
Toast.makeText(requireContext(), "Please fill out all fields.", Toast.LENGTH_LONG).show()
}
}
override fun onDestroy() {
super.onDestroy()
}
private fun inputCheck(firstName: String, lastName: String, age: String): Boolean{
return !(TextUtils.isEmpty(firstName) && TextUtils.isEmpty(lastName) && age.isEmpty())
}
}
ListFragment.kt
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import com.example.basehw.R
import com.example.basehw.databinding.FragmentListBinding
class ListFragment : Fragment() {
private var _binding: FragmentListBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
_binding = FragmentListBinding.inflate(inflater, container, false)
binding.floatingActionButton.setOnClickListener{
findNavController().navigate(R.id.action_listFragment_to_addFragment)
}
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
}
}
ListAdapter.kt
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.adapter.FragmentViewHolder
import com.example.basehw.R
import com.example.basehw.data.User
import com.example.basehw.databinding.ActivityMainBinding
import com.example.basehw.databinding.FragmentListBinding
class ListAdapter: RecyclerView.Adapter<ListAdapter.MyViewHolder>() {
private var binding: ActivityMainBinding? = null
private var userList = emptyList<User>()
class MyViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.custom_row, parent, false))
}
override fun getItemCount(): Int {
return userList.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = userList[position]
holder.itemView.id_txt.text = currentItem.id.toString()
holder.itemView.firstName_txt.text = currentItem.firstName
holder.itemView.lastName_txt.text = currentItem.lastName
holder.itemView.age_txt.text = currentItem.age.toString()
}
fun setData(user: List<User>){
this.userList = user
notifyDataSetChanged()
}
}
custom_row.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/custom_row"
android:padding="24sp">
<TextView
android:id="#+id/id_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/_1"
android:textSize="40sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/firstName_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="80dp"
android:text="#string/john"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="#+id/id_txt"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/lastName_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="#string/dao"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="#+id/firstName_txt"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/age_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:textSize="24sp"
android:text="#string/_25"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="#+id/lastName_txt"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
fragment_list.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.list.ListFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerview"
android:layout_width="409dp"
android:layout_height="729dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/floatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="24dp"
android:layout_marginBottom="24dp"
android:clickable="true"
android:focusable="true"
android:tint="#color/white"
android:src="#drawable/ic_add"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:ignore="SpeakableTextPresentCheck" />
</androidx.constraintlayout.widget.ConstraintLayout>
As Kotlinx.Synthetics has been deprecated, you should use view binding which you are already using in your fragment and activity, you should also use it in your RecyclerView adapter.
Make a few changes in your recycler view adapter to work with view bindings.
class ListAdapter: RecyclerView.Adapter<ListAdapter.MyViewHolder>() {
private var userList = emptyList<User>()
class MyViewHolder(private val customRowBinding: CustomRowBinding): RecyclerView.ViewHolder(customRowBinding.root) {
fun bind(user: User) {
customRowBinding.idTxt.text = user.id.toString()
customRowBinding.firstNameTxt.text = user.firstName
customRowBinding.lastNameTxt.text = user.lastName
customRowBinding.ageTxt.text = user.age.toString()
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(CustomRowBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}
override fun getItemCount(): Int {
return userList.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = userList[position]
holder.bind(currentItem)
}
fun setData(user: List<User>){
this.userList = user
notifyDataSetChanged()
}
}
Instead of binding data inside onBindViewHolder, create a bind() method inside the view holder and bind there.
Related
I just started programming using android. Currently, I want to set table layout in activity_main.xml like the picture below and retrieve/display data from SQL server database into it.
I have tried the following things.
I created some subclasses that interprets table in real database like ScanAdapter.java, ScanResultModel.java and I created also new layout scanresult.xml to provide identity of TextView in table row.
Set and design activity_main.xml
The problem is I don't know how to created the code to retrieve data from SQL database server. I did not find the solution.
Here is the activity_main.xml code
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<EditText
android:id="#+id/txtlabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:hint="Scan Label No"
android:minHeight="48dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.089" />
<EditText
android:id="#+id/txtqty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:hint="Enter Qty"
android:inputType="number"
android:minHeight="48dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.168" />
<EditText
android:id="#+id/txtrmrks"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:hint="Enter Remarks"
android:inputType="textAutoCorrect"
android:minHeight="48dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.244" />
<TextView
android:id="#+id/txtconnect"
android:layout_width="255dp"
android:layout_height="19dp"
android:text="con"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.41"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.99" />
<TextView
android:id="#+id/txtTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Scan Barcode Label"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.464"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.009" />
<Button
android:id="#+id/btn_scan"
android:layout_width="89dp"
android:layout_height="48dp"
android:text="Scan"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.027"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.948" />
<Button
android:id="#+id/btn_save"
android:layout_width="89dp"
android:layout_height="48dp"
android:text="Save"
app:backgroundTint="#8CD635"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.326"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.948" />
<Button
android:id="#+id/btn_load"
android:layout_width="89dp"
android:layout_height="48dp"
android:onClick="Loaddgv"
android:text="Load"
app:backgroundTint="#8CD635"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.627"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.948" />
<Button
android:id="#+id/btn_clear"
android:layout_width="89dp"
android:layout_height="48dp"
android:onClick="clearScan"
android:text="Clear"
app:backgroundTint="#8CD635"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.93"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.948" />
<TableLayout
android:layout_width="395dp"
android:layout_height="358dp"
android:layout_margin="8dp"
android:stretchColumns="1,2,3,4"
tools:context=".MainActivity"
tools:layout_editor_absoluteX="9dp"
tools:layout_editor_absoluteY="255dp"
android:background="#E8EEF3">
<TableRow
android:layout_height="1px"
android:background="#BDBDBD">
<TextView
android:layout_column="1"
android:gravity="center"
android:padding="10dp"
android:text="LabelNo"
android:textSize="16dp"
android:textStyle="bold" />
<TextView
android:layout_column="1"
android:gravity="center"
android:padding="10dp"
android:text="Qty"
android:textSize="16dp"
android:textStyle="bold" />
<TextView
android:layout_column="1"
android:gravity="center"
android:padding="10dp"
android:text="Remarks"
android:textSize="16dp"
android:textStyle="bold" />
<TextView
android:layout_column="1"
android:gravity="center"
android:padding="10dp"
android:text="ScanDate"
android:textSize="16dp"
android:textStyle="bold" />
</TableRow>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</TableLayout>
</androidx.constraintlayout.widget.ConstraintLayout >
MainActivity.java
package com.nid.shikakarikensa;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
public class MainActivity extends AppCompatActivity {
Connection connect;
String ConnectionResult;
private Button btnScan, btnSave, btnLoad, btnClear;
private TextView tstatus,tconnect, tusrid,msg;
private EditText trmrks, tqty, tlblno;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnScan = findViewById(R.id.btn_scan);
btnSave = findViewById(R.id.btn_save);
btnLoad = findViewById(R.id.btn_load);
btnClear = findViewById(R.id.btn_clear);
tstatus = findViewById(R.id.txtstatus);
tqty = findViewById(R.id.txtqty);
trmrks = findViewById(R.id.txtrmrks);
tusrid = findViewById(R.id.txtuserid);
tlblno = findViewById(R.id.txtlabel);
tconnect = findViewById(R.id.txtconnect);
tlblno.requestFocus();
tlblno.setEnabled(false);
btnScan.setOnClickListener(s ->
{
if (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
Manifest.permission.CAMERA)) {
startScan();
} else {
ActivityCompat.requestPermissions(MainActivity.this, new String[]
{Manifest.permission.CAMERA}, 0);
}
} else {
startScan();
}
});
btnSave.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String lblno = tlblno.getText().toString();
String qty = tqty.getText().toString();
if (lblno.isEmpty() || qty.isEmpty()){
Toast.makeText(MainActivity.this, "Please check your details data!", Toast.LENGTH_SHORT).show();
return;
}
SaveDataToDB(v);
tlblno.getText().clear();
tqty.getText().clear();
trmrks.getText().clear();
}
});
}
public void clearScan(View v)
{
tlblno.getText().clear();
tqty.getText().clear();
trmrks.getText().clear();
MessageBox("Data Cleared");
}
public void MessageBox(String message)
{
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
private void startScan()
{
Intent intent = new Intent(getApplicationContext(), ScannerActivity.class);
startActivityForResult(intent, 20);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 20) {
if (resultCode == RESULT_OK && data!=null) {
String code = data.getStringExtra("result");
tlblno.setText(code);
}
}
}
#Override
public void onRequestPermissionsResult (int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults)
{
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 0) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startScan();
} else {
Toast.makeText(this,"Failed to open camera!", Toast.LENGTH_LONG).show();
}
}
}
#SuppressLint("SetTextI18n")
public void SaveDataToDB(View v)
{
String lblno = tlblno.getText().toString();
String rmrks = trmrks.getText().toString();
String usrid = tusrid.getText().toString();
String value = tqty.getText().toString();
int qty=Integer.parseInt(value);
try {
ConnectionHelper connectionHelper = new ConnectionHelper();
connect = connectionHelper.connectionclass();
if (connect!=null) {
String query = "exec dbo.i_shikakarikensa '"+lblno+"', '"+qty+"', '"+rmrks+"','"+usrid+"' ";
Statement statement = connect.createStatement();
ResultSet result = statement.executeQuery(query);
Toast.makeText(MainActivity.this,"Data inserted",Toast.LENGTH_LONG).show();
} else {
ConnectionResult = "Database connection error";
}
}
catch (Exception ex)
{
Log.e("Set Error", ex.getMessage());
}
}
}
ScanAdapter.java
package com.nid.shikakarikensa;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class ScanAdapter extends RecyclerView.Adapter<ScanAdapter.ViewHolder> {
Context context;
List<ScanResultModel> scanresult_list;
public ScanAdapter(Context context, List<ScanResultModel> scanresult_list) {
this.context = context;
this.scanresult_list = scanresult_list;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.dgvscanrslt, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
if (scanresult_list != null && scanresult_list.size() > 0 ){
ScanResultModel model = scanresult_list.get(position);
holder.gvlabel.setText(model.getLabelNo());
holder.gvqty.setText(model.getQty());
holder.gvrmrks.setText(model.getRmrks());
holder.gvscandt.setText(model.getInsTs());
} else {
return;
}
}
#Override
public int getItemCount() {
return scanresult_list.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView gvlabel,gvqty,gvrmrks,gvscandt;
public ViewHolder(#NonNull View itemView) {
super(itemView);
gvlabel = itemView.findViewById(R.id.gvlabel);
gvqty = itemView.findViewById(R.id.gvqty);
gvrmrks = itemView.findViewById(R.id.gvrmrks);
gvscandt = itemView.findViewById(R.id.gvscandt);
}
}
}
ScanResultModel.java
package com.nid.shikakarikensa;
public class ScanResultModel {
String LabelNo, Qty, Rmrks, InsTs;
public ScanResultModel(String labelNo, String qty, String rmrks, String insTs) {
LabelNo = labelNo;
Qty = qty;
Rmrks = rmrks;
InsTs = insTs;
}
public String getLabelNo() {
return LabelNo;
}
public String getQty() {
return Qty;
}
public String getRmrks() {
return Rmrks;
}
public String getInsTs() {
return InsTs;
}
}
scanresult.xml
<?xml version="1.0" encoding="utf-8"?>
<TableLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="1"
android:orientation="vertical"
android:padding="5dp">
<TableRow>
<TextView
android:id="#+id/gvlabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#7F00FF"
android:textSize="17sp" />
<TextView
android:id="#+id/gvqty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#7F00FF"
android:textSize="17sp" />
<TextView
android:id="#+id/gvrmrks"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#7F00FF"
android:textSize="17sp" />
<TextView
android:id="#+id/gvscandt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#7F00FF"
android:textSize="17sp" />
</TableRow>
</TableLayout>
I'm having trouble uploading entities to the Cloud Datastore via the Apache Beam Java SDK (2.1.0). The following is my code:
import com.google.cloud.datastore.DatastoreOptions
import com.google.cloud.datastore.Entity
import com.opencsv.CSVParser
import org.apache.beam.runners.dataflow.DataflowRunner
import
org.apache.beam.runners.dataflow.options.DataflowPipelineOptions
import org.apache.beam.sdk.Pipeline
import org.apache.beam.sdk.io.TextIO
import org.apache.beam.sdk.io.gcp.datastore.DatastoreIO
import org.apache.beam.sdk.options.PipelineOptionsFactory
import org.apache.beam.sdk.transforms.DoFn
import org.apache.beam.sdk.transforms.MapElements
import org.apache.beam.sdk.transforms.ParDo
import org.apache.beam.sdk.transforms.SimpleFunction
import java.io.Serializable
object PipelineClass {
class FoodGroup(var id: String? = null,
var group: String? = null) : Serializable
class CreateGroupsFn : SimpleFunction<String, FoodGroup>() {
override fun apply(line: String?): FoodGroup {
val group = FoodGroup()
val parser = CSVParser()
val parts = parser.parseLine(line)
group.id = parts[0].trim()
group.group = parts[1].trim()
return group
}
}
class CreateEntitiesFn : DoFn<FoodGroup, Entity>() {
#ProcessElement
fun processElement(c: ProcessContext) {
val datastore = DatastoreOptions.getDefaultInstance().service
val keyFactory = datastore.newKeyFactory()
.setKind("FoodGroup")
.setNamespace("nutrients")
val key = datastore.allocateId(keyFactory.newKey())
val entity = Entity.newBuilder(key)
.set("id", c.element().id)
.set("group", c.element().group)
.build()
c.output(entity)
}
}
#JvmStatic fun main(args: Array<String>) {
val options =
PipelineOptionsFactory.`as`(DataflowPipelineOptions::class.java)
options.runner = DataflowRunner::class.java
options.project = "simplesample"
options.jobName = "fgUpload"
val pipeline = Pipeline.create(options)
pipeline.apply(TextIO.read().from("gs://bucket/foodgroup.csv"))
.apply(MapElements.via(CreateGroupsFn()))
.apply(ParDo.of(CreateEntitiesFn()))
//error occurs below...
.apply(DatastoreIO.v1().write()
.withProjectId(options.project))
pipeline.run()
}
}
The following is the error I get:
PipelineClass.kt: (75, 24): Type mismatch: inferred type is
DatastoreV1.Write! but PTransform<in PCollection<Entity!>!, PDone!>!
was expected
I've tried SimpleFunction, DoFn, and PTransform (composite and non-composite) to do the transform from String to Entity with no success.
What am I doing wrong?
EDIT: I've finally managed to get my entities in the Datastore. I decided to use Dataflow 1.9.1 and ditched Beam (2.1.0) after seeing this example. Below is my code:
import com.google.cloud.dataflow.sdk.Pipeline;
import com.google.cloud.dataflow.sdk.io.TextIO;
import com.google.cloud.dataflow.sdk.io.datastore.DatastoreIO;
import com.google.cloud.dataflow.sdk.options.Default;
import com.google.cloud.dataflow.sdk.options.Description;
import com.google.cloud.dataflow.sdk.options.PipelineOptions;
import com.google.cloud.dataflow.sdk.options.PipelineOptionsFactory;
import com.google.cloud.dataflow.sdk.transforms.DoFn;
import com.google.cloud.dataflow.sdk.transforms.ParDo;
import com.google.datastore.v1.Entity;
import com.google.datastore.v1.Key;
import com.opencsv.CSVParser;
import javax.annotation.Nullable;
import java.util.UUID;
import static com.google.datastore.v1.client.DatastoreHelper.makeKey;
import static
com.google.datastore.v1.client.DatastoreHelper.makeValue;
public class PipelineClass {
static class CreateEntitiesFn extends DoFn<String, Entity> {
private final String namespace;
private final String kind;
private final Key ancestorKey;
CreateEntitiesFn(String namespace, String kind) {
this.namespace = namespace;
this.kind = kind;
ancestorKey = makeAncestorKey(namespace, kind);
}
Entity makeEntity(String id, String group) {
Entity.Builder entityBuilder = Entity.newBuilder();
Key.Builder keyBuilder = makeKey(ancestorKey, kind,
UUID.randomUUID().toString());
if (namespace != null) {
keyBuilder.getPartitionIdBuilder().setNamespaceId(namespace);
}
entityBuilder.setKey(keyBuilder.build());
entityBuilder.getMutableProperties().put("id",
makeValue(id).build());
entityBuilder.getMutableProperties().put("group",
makeValue(group).build());
return entityBuilder.build();
}
#Override
public void processElement(ProcessContext c) throws Exception {
CSVParser parser = new CSVParser();
String[] parts = parser.parseLine(c.element());
String id = parts[0];
String group = parts[1];
c.output(makeEntity(id, group));
}
}
static Key makeAncestorKey(#Nullable String namespace, String kind) {
Key.Builder keyBuilder = makeKey(kind, "root");
if (namespace != null) {
keyBuilder.getPartitionIdBuilder().setNamespaceId(namespace);
}
return keyBuilder.build();
}
public interface Options extends PipelineOptions {
#Description("Path of the file to read from and store to Cloud
Datastore")
#Default.String("gs://bucket/foodgroup.csv")
String getInput();
void setInput(String value);
#Description("Dataset ID to read from Cloud Datastore")
#Default.String("simplesample")
String getProject();
void setProject(String value);
#Description("Cloud Datastore Entity Kind")
#Default.String("FoodGroup")
String getKind();
void setKind(String value);
#Description("Dataset namespace")
#Default.String("nutrients")
String getNamespace();
void setNamespace(#Nullable String value);
#Description("Number of output shards")
#Default.Integer(0)
int getNumShards();
void setNumShards(int value);
}
public static void main(String args[]) {
PipelineOptionsFactory.register(Options.class);
Options options =
PipelineOptionsFactory.fromArgs(args).as(Options.class);
Pipeline p = Pipeline.create(options);
p.apply(TextIO.Read.named("ReadLines").from(options.getInput()))
.apply(ParDo.named("CreateEntities").of(new
CreateEntitiesFn(options.getNamespace(), options.getKind())))
.apply(DatastoreIO.v1().write().withProjectId(options.getProject()));
p.run();
}
}
This is very much a work in progress so I apologize for my code needing to be cleaned up, but I thought it best to include everything I have so far.
I'm trying to figure how to animate text by looping through an array of images. My code loops through the array and displays just the last image. I need to display one image at a time and repeat to give the desired animation effect. What am I doing wrong or not doing?
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.stage.Stage;
import javafx.util.Duration;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.event.EventHandler;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
public class ImageAnimatorWithAudio extends Application {
private final static int NUMBER_OF_SLIDES = 10;
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
Image[] images = new Image[NUMBER_OF_SLIDES];
Timeline animation = new Timeline(new KeyFrame(Duration.millis(5000)));
animation.setCycleCount(Timeline.INDEFINITE);
animation.play();
HBox hBox = new HBox();
hBox.setSpacing(10);
hBox.setAlignment(Pos.TOP_RIGHT);
Button btStartPause = new Button("Start Animation");
hBox.getChildren().add(btStartPause);
//Create border pane
BorderPane borderPane = new BorderPane();
borderPane.setTop(hBox); //Add hBox to borderPane
BorderPane.setAlignment(hBox, Pos.TOP_RIGHT); //Align hBox
btStartPause.setOnAction(e -> {
if (btStartPause.getText().equals("Start Animation")) {
btStartPause.setText("Pause Animation");
animation.play();
} else {
btStartPause.setText("Start Animation");
animation.pause();
}
});
GridPane pane = new GridPane();
pane.setPadding(new Insets(5,5,5,5));
for (int i = 0; i < NUMBER_OF_SLIDES; i++) {
images[i] = new Image("image_path" + i + ".png"); //file names are numerically named(i)
pane.getChildren().add(new ImageView(images[i]));
}
pane.getChildren().add(borderPane);
Scene scene = new Scene(pane, 450, 450);
primaryStage.setTitle("TextAnimation"); //Set the stage title
primaryStage.setScene(scene); //Place the scene in the stage
primaryStage.show(); //Display the stage
}
public static void main(String[] args){
Application.launch(args);
}
}
Any help is appreciated.
Here is an app that demonstrates how to add Images to an ArrayList(similar approach for an Array). It also demonstrates how to load those Images into an ImageView and change them using Timeline.
Main
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
*
* #author Sedrick
*/
public class JavaFXApplication1 extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="371.0" prefWidth="607.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.60" fx:controller="javafxapplication1.FXMLDocumentController">
<children>
<Button fx:id="btnMain" layoutX="263.0" layoutY="326.0" onAction="#handleButtonAction" text="Click Me!" />
<Label fx:id="lblMain" layoutX="269.0" layoutY="28.0" minHeight="16" minWidth="69" />
<ImageView fx:id="ivMain" fitHeight="201.0" fitWidth="278.0" layoutX="165.0" layoutY="85.0" pickOnBounds="true" preserveRatio="true" />
</children>
</AnchorPane>
Controller
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.util.Duration;
/**
*
* #author Sedrick
*/
public class FXMLDocumentController implements Initializable {
#FXML private Label lblMain;
#FXML private ImageView ivMain;
#FXML private Button btnMain;
Timeline timeline;
List<Image> imageContainer;
int currentImageBeingDisplayed;
#FXML
private void handleButtonAction(ActionEvent event) {
lblMain.setText("Animation started!");
currentImageBeingDisplayed = 0;
timeline.play();
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
//Load images
imageContainer = new ArrayList();
for(int i = 1; i <= 12; i++)
{
try
{
System.out.println("/images/Slide" + i + ".PNG");
imageContainer.add(new Image(getClass().getResource("/images/Slide" + i + ".PNG").toURI().toString()));
} catch (URISyntaxException ex) {
System.out.println(ex.toString());
}
}
//Change the image every second
timeline = new Timeline(
new KeyFrame(
Duration.seconds(1),
new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent actionEvent) {
Platform.runLater(()->{
ivMain.setImage(imageContainer.get(currentImageBeingDisplayed++));
});
}
}
)
);
timeline.setCycleCount(12);
}
}
Output:(looks similar to below)
I have number of objects. Let's say i have 10 Books object and i want user to select any number of the book. When user press the submit button i want to retrieve all the books "object" that user selected.
As of now, while showing screen to user i use
CheckBox cb= new CheckBox(book.getName());
this shows bookname to user and user selects the book. But on runtime i will be needing bookid and other properties of book object as well.
Is there anyway through which i can save the book object in the checkbox?
Basic Examle. if you want more sepecifc you need to post your code, we can set object to node using setUserDate, then we can use that object when we need. here i am using object id for example, in yor case save that object i hope this will solve your problem ,?s post a comment
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class UserData extends Application {
public void start(Stage primaryStage) {
VBox root = new VBox();
Book book = new Book(22, "firstBok");
Book book1 = new Book(2, "secondBok");
CheckBox checkB = new CheckBox(book.getName());
checkB.setUserData(book);
CheckBox checkB1 = new CheckBox(book1.getName());
checkB1.setUserData(book1);
Button btn = new Button("Submit");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if (checkB.isSelected()) {
int firstCheckBxId = ((Book) checkB.getUserData()).getId();
System.out.println("id:" + firstCheckBxId);
}
if (checkB1.isSelected()) {
int secondCheckBxId = ((Book) checkB1.getUserData()).getId();
System.out.println("id:" + secondCheckBxId);
}
}
});
root.getChildren().addAll(checkB, checkB1, btn);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
class Book {
int id;
private String name;
Book(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return this.id;
}
public String getName() {
return name;
}
}
public static void main(String[] args) {
launch(args);
}
}
Consider using a control with built-in selection functionality, such as a ListView. Then you can just check the selection model.
import java.util.stream.IntStream;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class BookSelection extends Application {
#Override
public void start(Stage primaryStage) {
ListView<Book> bookList = new ListView<>();
bookList.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
bookList.setCellFactory(lv -> new ListCell<Book>() {
#Override
public void updateItem(Book book, boolean empty) {
super.updateItem(book, empty);
if (empty) {
setText(null);
} else {
setText(book.getTitle());
}
}
});
IntStream.rangeClosed(1, 10).mapToObj(i -> new Book("Book "+i)).forEach(bookList.getItems()::add);
Button submit = new Button("Submit selection");
submit.setOnAction(e ->
bookList.getSelectionModel().getSelectedItems().forEach(book -> System.out.println(book.getTitle())));
BorderPane root = new BorderPane(bookList, null, null, submit, null);
BorderPane.setAlignment(submit, Pos.CENTER);
BorderPane.setMargin(submit, new Insets(10));
Scene scene = new Scene(root, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static class Book {
private final StringProperty title = new SimpleStringProperty() ;
public Book(String title) {
setTitle(title);
}
public final StringProperty titleProperty() {
return this.title;
}
public final java.lang.String getTitle() {
return this.titleProperty().get();
}
public final void setTitle(final java.lang.String title) {
this.titleProperty().set(title);
}
}
public static void main(String[] args) {
launch(args);
}
}
If for some reason you really want to implement this with check boxes, you can keep a Set<Book> representing the selected books, and update it when each check box is selected/unselected. Note this is similar to #user99370's answer, but is more robust as it avoids downcasting the (essentially unknown-type) userData to your data type.
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class BookSelection extends Application {
#Override
public void start(Stage primaryStage) {
GridPane grid = new GridPane();
grid.setHgap(5);
grid.setVgap(5);
grid.setPadding(new Insets(10 ));
List<Book> books = IntStream.rangeClosed(1, 10).mapToObj(i -> new Book("Book "+i)).collect(Collectors.toList());
Set<Book> selectedBooks = new HashSet<>();
int row = 0 ;
for (Book book : books) {
CheckBox checkBox = new CheckBox();
checkBox.selectedProperty().addListener((obs, wasSelected, isNowSelected) -> {
if (isNowSelected) {
selectedBooks.add(book);
} else {
selectedBooks.remove(book);
}
});
grid.addRow(row, checkBox, new Label(book.getTitle()));
row++ ;
}
Button submit = new Button("Submit selection");
submit.setOnAction(e ->
selectedBooks.forEach(book -> System.out.println(book.getTitle())));
GridPane.setHalignment(submit, HPos.CENTER);
grid.add(submit, 0, row, 2, 1);
Scene scene = new Scene(grid, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static class Book {
private final StringProperty title = new SimpleStringProperty() ;
public Book(String title) {
setTitle(title);
}
public final StringProperty titleProperty() {
return this.title;
}
public final java.lang.String getTitle() {
return this.titleProperty().get();
}
public final void setTitle(final java.lang.String title) {
this.titleProperty().set(title);
}
}
public static void main(String[] args) {
launch(args);
}
}
This is just a simplified version of the accepted answer.
We can use setUserData(Object) to set data and getUserData() to retrieve the previously set data of any JavaFX node (including CheckBox).
Reference:
https://docs.oracle.com/javase/8/javafx/api/javafx/scene/Node.html#setUserData-java.lang.Object-
I would like to update my combobox when the content of the object used to display text in combo changes.
Here is a sample:
package com.javafx.example.combobox;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;
import javafx.util.StringConverter;
public class ComboboxSample extends Application {
class Sequence {
public StringProperty name = new SimpleStringProperty();
public Sequence(String name) {
super();
this.name.set(name);
}
#Override
public String toString() {
return "null";
}
}
#Override
public void start(Stage stage) throws Exception {
stage.setTitle("ComboBoxSample");
ComboBox<Sequence> combo = new ComboBox<>();
combo.setItems(FXCollections.observableArrayList(
new Sequence("Toto"),
new Sequence("Titi")));
combo.getSelectionModel().selectFirst();
combo.setConverter(new StringConverter<ComboboxSample.Sequence>() {
#Override
public String toString(Sequence sequence) {
return sequence.name.get();
}
#Override
public Sequence fromString(String string) {
System.out.println("call fromString");
return null;
}
});
TextField text = new TextField();
Button renameButton = new Button("Rename");
renameButton.setOnAction(evt -> combo.getValue().name.set(text.getText()));
HBox root = new HBox(combo, text, renameButton);
HBox.setHgrow(text, Priority.ALWAYS);
stage.setScene(new Scene(root));
stage.show();
}
public static void main(String... args) {
launch(args);
}
}
The combobox contains objects with a property name. If i rename this property, the display do not change or sometimes it changes but not all the time. It is the standard behavior as the combobox update when the object changes, and not when its content changes.
How can i do to force the combobox to refresh its value and the listview on change?
Thanks
EDIT1:
Using a callback in an observaleList seems to be a solution.
package com.javafx.example.combobox;
import javafx.application.Application;
import javafx.beans.Observable;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.util.StringConverter;
public class ComboboxSample extends Application {
ObservableList<Sequence> sequences;
class Sequence {
public StringProperty name = new SimpleStringProperty();
public Sequence(String name) {
super();
this.name.set(name);
}
#Override
public String toString() {
return "null";
}
}
#Override
public void start(Stage stage) throws Exception {
stage.setTitle("ComboBoxSample");
Callback<Sequence, Observable[]> extractor = new Callback<Sequence, Observable[]>() {
#Override
public Observable[] call(Sequence s) {
return new Observable[] {s.name};
}
};
sequences = FXCollections.observableArrayList(extractor);
sequences.addAll(
new Sequence("Toto"),
new Sequence("Titi"));
ComboBox<Sequence> combo = new ComboBox<>();
combo.setItems(sequences);
combo.getSelectionModel().selectFirst();
combo.setConverter(new StringConverter<ComboboxSample.Sequence>() {
#Override
public String toString(Sequence sequence) {
return sequence.name.get();
}
#Override
public Sequence fromString(String string) {
System.out.println("call fromString");
return null;
}
});
combo.valueProperty().addListener((obs, oldValue, newValue) -> System.out.println("Change from " + oldValue.name.get() + " to " + newValue.name.get()));
TextField text = new TextField();
Button renameButton = new Button("Rename");
renameButton.setOnAction(evt -> {
combo.getValue().name.set(text.getText());
});
HBox root = new HBox(combo, text, renameButton);
HBox.setHgrow(text, Priority.ALWAYS);
stage.setScene(new Scene(root));
stage.show();
}
public static void main(String... args) {
launch(args);
}
}
Everytime a new value is added to the object list, set the combobox value again. Works for me. I did a small example to show this. Hope it is helpful
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ComboTest extends Application {
int i =0;
ObservableList<String> list = FXCollections.observableArrayList("A","B");
ComboBox<String> combo = new ComboBox();
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
combo.setPromptText("Testing combobox");
combo.setPrefWidth(300);
btn.setText("Add items to list");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
list.add(String.valueOf(i));
System.out.println("size of list " + list.size() );
i++;
combo.setItems(list);
}
});
combo.setItems(list);
VBox root = new VBox();
root.getChildren().addAll(btn,combo);
root.setSpacing(20);
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}