overlapping images in grid layout
11 visualizzazioni (ultimi 30 giorni)
Mostra commenti meno recenti
I am trying to create a solitaire card game app (think FreeCell) using App Designer. To graphically display the tableau, my idea is to represent the cards as images in a Grid Layout, which would nicely handle the user resizing the app window. However, the grid cells need to be shorter than the card images, as some cards need to partially overlap others (the image shows some notional grid cells outlined in cyan). More to the point, in order for the top (lowest on screen) card to be fully visible, the card images need to be able to spill out below their cells. I do not see a way to allow that in App Designer's grid layout. Is that possible, or is there a better way to display the overlapping card images?
What I have so far (in the screenshot) is a one-row grid for the bottom cards (those that are highest in the app window) and the other cards are not on a grid. This works perfectly as long as the window is not resized.
0 Commenti
Risposta accettata
Adam Danz
il 22 Set 2023
Modificato: Adam Danz
il 22 Set 2023
I would suggest a different approach. You could potentially have dozens of axes and just as many images in your app which could result in sluggish responses of the app. You'd also need to manage the uistack to ensure that various graphics objects are stacked in the correct order. It sounds like it could be a mess.
Are you stuck to using images? The cards could be simulated using text and rectangles within a single axes.
Here's a demo to get you started. At the end, I'll show how to work with these objects once they are plotted.
deck = ["A"; (2:10)';'J';'Q';'K'] + ["♥","♦","♠","♣"]
deckColors = repelem(["r","r","k","k"],height(deck),1)
Specify number of cards in each stack
For simplicity, the number of cards are hard-coded in this demo.
% Indicate the number of cards in each stack
nCards = [5 2 4 6 4]; % number of cards in each stack
nStacks = numel(nCards); % number of vertical stacks
Compute card size and position
% Compute the x-coordinates of the left edge of each stack
% where all cards are within [0,1] x-limits.
gap = 0.05; % horizontal gap between stacks
cardWidth = ((1-2*gap)-(gap*(nStacks-1)))/nStacks;
xStack = gap:(cardWidth+gap):(1-gap);
% Compute card height
cardHeight = 1.4286 * cardWidth; % based on actual playing card dimensions
% Specify the vertical shift - how much of each card will show (except the
% bottom ones)
yShift = 0.3; % Percentage of card-height
Randomly select cards
This uses randperm to avoid duplicates
% Select a random set of cards without duplicates
randIdx = randperm(numel(deck),sum(nCards));
randCards = deck(randIdx);
randCardColors = deckColors(randIdx);
Plot the cards in an axes
The demo creates a new figure and axes but you can replace this with your app's figure and axes handles.
% Create the cards in an axes
fig = figure('Color',[0 .5 0]);
ax = axes(fig,'Position',[0 0 1 1]);
xlim(ax,[0,1])
ylim(ax,[-inf,0]);
hold(ax,'on')
% Loop through each stack
cardObjs = gobjects(1,sum(nCards));
for i = 1:nStacks
% Compute y vertical position of bottom edge of all cards in this stack
% from the top card to the bottom card.Note that the top edge of the
% axes will be 0 and the bottom edge will be some negative value.
yStack = (-gap-cardHeight) : -(yShift*cardHeight) : (-gap-cardHeight)-(nCards(i)*(yShift*cardHeight));
% Loop through each card
for j = 1:nCards(i)
n = sum(nCards(1:(i-1)))+j; % n^th total card
cardObjs(n) = hggroup(ax);
% Card rectangle
cardPosition = [xStack(i), yStack(j), cardWidth, cardHeight];
rectangle('parent',cardObjs(n), ...
'Position', cardPosition, ...
'Curvature', 0.3, ...
'FaceColor','w');
% Card face (text), position is at top, middle of card
text('parent',cardObjs(n), ...
'String', randCards(n), ...
'Color', randCardColors(n), ...
'FontSize', 18, ... % adjust as needed or better yet, compute it
'Position', [cardPosition(1)+cardWidth/2, cardPosition(2)+cardHeight, 0],...
'HorizontalAlignment', 'Center', ...
'VerticalAlignment', 'top');
end
end
% Tidy up the plot
axis equal off
Now that some cards exist, you can work with them using their handles which are Group objects created by hggroup, stored in variable cardObjs.
Each group contains a rectangle and text object. You can delete the k^th group using delete(cardObjs(k)).
Change the position of a card by updating the Position properties of each child of the group.
cardObjs(k).Children(1).Position % text
cardObjs(k).Children(2).Position % rectangle
Since the cards will change position frequently, you could write a helper function to do this. You could also add a listener to the text object in each group so that it follows the rectangle. That way you'd only need to update the position of the rectange.
As you can probably imagine, there's a lot of flexibility here and with that, I'll hand it off to you. Good luck!
7 Commenti
Adam Danz
il 6 Ott 2023
Hi Rich006, that sounds reasonable. You could also change how yStack and the axis limits are computed. Sounds like you're in control of it 😊
Più risposte (0)
Vedere anche
Categorie
Scopri di più su Develop Apps Using App Designer in Help Center e File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!