Compose For Desktopでアイコンを表示する

Compose For Desktopでアイコンを表示する方法について。

使えるアイコン

アイコンのテーマには、塗りつぶし、アウトライン、丸め、TwoTone、シャープがある。

アイコンは次のパッケージに用意されている。

  • androidx.compose.material.icons.Icons.Filled
  • androidx.compose.material.icons.Icons.Outlined
  • androidx.compose.material.icons.Icons.Rounded
  • androidx.compose.material.icons.Icons.Sharp
  • androidx.compose.material.icons.Icons.TwoTone

アイコンを表示する

アイコンを表示するにはIcon()関数を使用する。

Icon(
    Icons.Filled.Search,
    contentDescription = "Icons.Filled.Search",
    modifier = Modifier.width(64.dp).height(64.dp)
)

アイコンボタンを表示する

クリック可能なアイコンを表示するには、IconButton()関数を使用する。

IconButton(
    modifier = Modifier.width(64.dp).height(64.dp),
    onClick = { println("Icons.Filled.Home") }) {
    Icon(
        Icons.Filled.Home,
        contentDescription = "Icons.Filled.Home",
        modifier = Modifier.width(64.dp).height(64.dp)
    )
}

ボタンにアイコンを表示する

ボタンの中にアイコンを表示するには、Button()関数の中でIcon()関数を使用する。

アイコンのフォルトサイズと、アイコンとテキストの間隔のデフォルトサイズが定義されている。

ButtonDefaults.IconSizeは、ボタン内でアイコンを使用する場合のアイコンのデフォルトサイズ。
ButtonDefaults.IconSpacingは、ボタン内でアイコンとテキストを使用する場合の間隔のデフォルトサイズ。

Button(onClick = { println("Icons.Filled.Favorite") }) {
    Icon(
        Icons.Filled.Favorite,
        contentDescription = "Icons.Filled.Favorite",
        modifier = Modifier.size(ButtonDefaults.IconSize)
    )
    Spacer(Modifier.size(ButtonDefaults.IconSpacing))
    Text(text = "Icons.Filled.Favorite")
}

拡張フローティングアクションボタンを使用する

拡張フローティングアクションボタンを表示するには、ExtendedFloatingActionButton()を使用する。

ExtendedFloatingActionButton(
    text = { Text("Icons.Filled.Refresh") },
    icon = { Icon(Icons.Filled.Refresh, contentDescription = "Icons.Filled.Refresh") },
    onClick = { println("Icons.Outlined.Favorite") }
)

サンプルプログラム

サンプルプログラムのソースコード。
 

fun main() = application {
    Window(
        onCloseRequest = ::exitApplication,
        title = "Compose for Desktop",
        state = rememberWindowState(width = 340.dp, height = 380.dp)
    ) {
        val rowModifier = Modifier.fillMaxWidth().padding(bottom=16.dp)

        MaterialTheme {
            Column(modifier = Modifier.fillMaxHeight().fillMaxWidth().padding(4.dp)) {
                Text(text = "Icon")
                Row(modifier = rowModifier) {
                    Icon(
                        Icons.Filled.Search,
                        contentDescription = "Icons.Filled.Search",
                        modifier = Modifier.width(64.dp).height(64.dp)
                    )
                }
                Text(text = "IconButton")
                Row(modifier = rowModifier) {
                    IconButton(
                        modifier = Modifier.width(64.dp).height(64.dp),
                        onClick = { println("Icons.Filled.Home") }) {
                        Icon(
                            Icons.Filled.Home,
                            contentDescription = "Icons.Filled.Home",
                            modifier = Modifier.width(64.dp).height(64.dp)
                        )
                    }
                }
                Text(text = "Button")
                Row(modifier = rowModifier) {
                    Button(onClick = { println("Icons.Filled.Favorite") }) {
                        Icon(
                            Icons.Filled.Favorite,
                            contentDescription = "Icons.Filled.Favorite",
                            modifier = Modifier.size(ButtonDefaults.IconSize)
                        )
                        Spacer(Modifier.size(ButtonDefaults.IconSpacing))
                        Text(text = "Icons.Filled.Favorite")
                    }
                }
                Text(text = "ExtendedFloatingActionButton")
                Row(modifier = rowModifier) {
                    ExtendedFloatingActionButton(
                        text = { Text("Icons.Filled.Refresh") },
                        icon = { Icon(Icons.Filled.Refresh, contentDescription = "Icons.Filled.Refresh") },
                        onClick = { println("Icons.Outlined.Favorite") }
                    )
                }
            }
        }
    }
}

LaravelでEagerローディングを使って削除済み(Trashed)モデルをロードするには

LaravelでEagerローディングを使って削除済み(Trashed)のモデルをロードする方法。

Eagerロードクエリの条件にwithTrashed()を追加します。

$order = Order::with(['user' => function ($query) {
        $query->withTrashed();
    }])

Compose for Desktopでウィンドウにドロップされたファイルを取得するには

Compose for Desktopでウィンドウにドロップされたファイルを取得する方法について。

環境

  • Compose for Desktop 1.0.0-alpha3

問題

Compose For Desktopでウィンドウにドロップされたファイルを取得したい。

方法

FrameWindowScopeのwindowはComposeWindowです。
ComposeWindowはjavax.swing.JFrameを継承した、Compose for Desktopのためのウィンドウです。

ComposeWindowがドロップ受け取れるようにDropTargetを関連付け、ドロップされたファイルを受け取ります。

import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.window.singleWindowApplication
import java.awt.datatransfer.DataFlavor
import java.awt.dnd.DnDConstants
import java.awt.dnd.DropTarget
import java.awt.dnd.DropTargetAdapter
import java.awt.dnd.DropTargetDropEvent

fun main() = singleWindowApplication {
    LaunchedEffect(Unit) {
        window.dropTarget = DropTarget().apply {
            addDropTargetListener(object : DropTargetAdapter() {
                override fun drop(event: DropTargetDropEvent) {
                    event.acceptDrop(DnDConstants.ACTION_COPY);
                    val fileName = event.transferable.getTransferData(DataFlavor.javaFileListFlavor)
                    println(fileName)
                }
            })
        }
    }
}

Compose for DesktopのMouse_Eventsのチュートリアルをやってみた

Compose for DesktopのMouse_Eventsのチュートリアルをやってみた。

環境

  • Compose for Desktop 1.0.0-alpha3

参考

Clickイベント

クリック・ダブルクリック・ロングクリックを取得できる。

fun main() = singleWindowApplication {
    @OptIn(ExperimentalFoundationApi::class)
    Box(
        modifier = Modifier
            .background(Color.Magenta)
            .fillMaxWidth(0.5f)
            .fillMaxHeight(0.5f)
            .combinedClickable(
                onClick = { println("onClick") },
                onDoubleClick = { println("onDoubleClick") },
                onLongClick = { println("onLongClick") },
            )
    )
}

moveイベント

マウスカーソルの移動が移動したイベントを取得できる。

fun main() = singleWindowApplication {
    Box(
        modifier = Modifier
            .background(Color.Magenta)
            .fillMaxWidth(0.5f)
            .fillMaxHeight(0.5f)
            .pointerMoveFilter(
                onMove = {
                    println("x:${it.x} y:${it.y}")
                    false
                }
            )
    )
}

enterイベント

マウスカーソルがコンポーネントの領域に入った/出たときのイベントを取得できる。

fun main() = singleWindowApplication {
    Box(
        modifier = Modifier
            .background(Color.Magenta)
            .fillMaxWidth(0.5f)
            .fillMaxHeight(0.5f)
            .pointerMoveFilter(
                onEnter = {
                    println("Enter")
                    false
                },
                onExit = {
                    println("Exit")
                    false
                }
            )
    )
}

右クリック・中クリックと修飾キー

押されたマウスのボタンと修飾キーを取得できる。

イベントに関する詳細情報が必要な場合は、PointerEventのmou​​seEventプロパティに利用可能な生のAWTマウスイベントオブジェクトがある。

@OptIn(ExperimentalDesktopApi::class)
fun main() = singleWindowApplication {
    var clickableText by remember { mutableStateOf("Click me!") }

    Column {
        Box(
            modifier = Modifier
                .background(Color.Magenta)
                .fillMaxWidth(0.5f)
                .fillMaxHeight(0.5f)
                .mouseClickable(
                    onClick = {
                        clickableText = buildString {
                            append("Buttons pressed:\n")
                            append("primary: ${buttons.isPrimaryPressed}\t")
                            append("secondary: ${buttons.isSecondaryPressed}\t")
                            append("tertiary: ${buttons.isTertiaryPressed}\t")

                            append("\n\nKeyboard modifiers pressed:\n")

                            append("alt: ${keyboardModifiers.isAltPressed}\t")
                            append("ctrl: ${keyboardModifiers.isCtrlPressed}\t")
                            append("meta: ${keyboardModifiers.isMetaPressed}\t")
                            append("shift: ${keyboardModifiers.isShiftPressed}\t")
                        }
                    }
                )
        )
        Text(
            text = clickableText
        )
    }
}